pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00067 /* #define DEBUG_MENUS */ 00068 00069 #ifdef HAVE_CONFIG_H 00070 #include "config.h" 00071 #endif 00072 00073 #include <unistd.h> 00074 00075 #include "ghid-layer-selector.h" 00076 #include "ghid-route-style-selector.h" 00077 #include "gtkhid.h" 00078 #include "gui.h" 00079 #include "hid.h" 00080 #include "../hidint.h" 00081 #include "hid/common/hid_resource.h" 00082 00083 #include "action.h" 00084 #include "autoplace.h" 00085 #include "autoroute.h" 00086 #include "buffer.h" 00087 #include "change.h" 00088 #include "copy.h" 00089 #include "create.h" 00090 #include "crosshair.h" 00091 #include "draw.h" 00092 #include "error.h" 00093 #include "file.h" 00094 #include "find.h" 00095 #include "gpcb-menu.h" 00096 #include "insert.h" 00097 #include "line.h" 00098 #include "mymem.h" 00099 #include "misc.h" 00100 #include "move.h" 00101 #include "pcb-printf.h" 00102 #include "polygon.h" 00103 #include "rats.h" 00104 #include "remove.h" 00105 #include "report.h" 00106 #include "resource.h" 00107 #include "rotate.h" 00108 #include "rubberband.h" 00109 #include "search.h" 00110 #include "select.h" 00111 #include "set.h" 00112 #include "undo.h" 00113 #include "vendor.h" 00114 #include "free_atexit.h" 00115 00116 #include "gui-icons-mode-buttons.data" 00117 #include "gui-icons-misc.data" 00118 #include "gui-trackball.h" 00119 00120 #ifdef HAVE_LIBDMALLOC 00121 #include <dmalloc.h> 00122 #endif 00123 00124 static bool ignore_layer_update; 00125 00126 static GtkWidget *ghid_load_menus (void); 00127 00128 GhidGui _ghidgui, *ghidgui = NULL; 00129 00130 GHidPort ghid_port, *gport; 00131 00132 static gchar *bg_image_file; 00133 00134 static struct { GtkAction *action; const Resource *node; } 00135 ghid_hotkey_actions[256]; 00136 #define N_HOTKEY_ACTIONS \ 00137 (sizeof (ghid_hotkey_actions) / sizeof (ghid_hotkey_actions[0])) 00138 00139 00143 void 00144 menu_toggle_update_cb (GtkAction *act, const char *tflag, const char *aflag) 00145 { 00146 if (tflag != NULL) 00147 { 00148 int v = hid_get_flag (tflag); 00149 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (act), !!v); 00150 } 00151 if (aflag != NULL) 00152 { 00153 int v = hid_get_flag (aflag); 00154 gtk_action_set_sensitive (act, !!v); 00155 } 00156 } 00157 00161 void 00162 ghid_update_toggle_flags () 00163 { 00164 ghid_main_menu_update_toggle_state (GHID_MAIN_MENU (ghidgui->menu_bar), 00165 menu_toggle_update_cb); 00166 } 00167 00168 static void 00169 h_adjustment_changed_cb (GtkAdjustment * adj, GhidGui * g) 00170 { 00171 if (g->adjustment_changed_holdoff) 00172 return; 00173 00174 ghid_port_ranges_changed (); 00175 } 00176 00177 static void 00178 v_adjustment_changed_cb (GtkAdjustment * adj, GhidGui * g) 00179 { 00180 if (g->adjustment_changed_holdoff) 00181 return; 00182 00183 ghid_port_ranges_changed (); 00184 } 00185 00186 /* Save size of top window changes so PCB can restart at its size at exit. 00187 */ 00188 static gint 00189 top_window_configure_event_cb (GtkWidget * widget, GdkEventConfigure * ev, 00190 GHidPort * port) 00191 { 00192 GtkAllocation allocation; 00193 gboolean new_w, new_h; 00194 00195 gtk_widget_get_allocation (widget, &allocation); 00196 00197 new_w = (ghidgui->top_window_width != allocation.width); 00198 new_h = (ghidgui->top_window_height != allocation.height); 00199 00200 ghidgui->top_window_width = allocation.width; 00201 ghidgui->top_window_height = allocation.height; 00202 00203 if (new_w || new_h) 00204 ghidgui->config_modified = TRUE; 00205 00206 return FALSE; 00207 } 00208 00209 static void 00210 info_bar_response_cb (GtkInfoBar *info_bar, 00211 gint response_id, 00212 GhidGui *_gui) 00213 { 00214 gtk_widget_destroy (_gui->info_bar); 00215 _gui->info_bar = NULL; 00216 00217 if (response_id == GTK_RESPONSE_ACCEPT) 00218 RevertPCB (); 00219 } 00220 00221 static void 00222 close_file_modified_externally_prompt (void) 00223 { 00224 if (ghidgui->info_bar != NULL) 00225 gtk_widget_destroy (ghidgui->info_bar); 00226 ghidgui->info_bar = NULL; 00227 } 00228 00229 static void 00230 show_file_modified_externally_prompt (void) 00231 { 00232 GtkWidget *button; 00233 GtkWidget *button_image; 00234 GtkWidget *icon; 00235 GtkWidget *label; 00236 GtkWidget *content_area; 00237 char *file_path_utf8; 00238 char *secondary_text; 00239 char *markup; 00240 00241 close_file_modified_externally_prompt (); 00242 00243 ghidgui->info_bar = gtk_info_bar_new (); 00244 00245 button = gtk_info_bar_add_button (GTK_INFO_BAR (ghidgui->info_bar), 00246 _("Reload"), 00247 GTK_RESPONSE_ACCEPT); 00248 button_image = gtk_image_new_from_stock (GTK_STOCK_REFRESH, 00249 GTK_ICON_SIZE_BUTTON); 00250 gtk_button_set_image (GTK_BUTTON (button), button_image); 00251 00252 gtk_info_bar_add_button (GTK_INFO_BAR (ghidgui->info_bar), 00253 GTK_STOCK_CANCEL, 00254 GTK_RESPONSE_CANCEL); 00255 gtk_info_bar_set_message_type (GTK_INFO_BAR (ghidgui->info_bar), 00256 GTK_MESSAGE_WARNING); 00257 gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle), 00258 ghidgui->info_bar, FALSE, FALSE, 0); 00259 gtk_box_reorder_child (GTK_BOX (ghidgui->vbox_middle), ghidgui->info_bar, 0); 00260 00261 00262 g_signal_connect (ghidgui->info_bar, "response", 00263 G_CALLBACK (info_bar_response_cb), ghidgui); 00264 00265 file_path_utf8 = g_filename_to_utf8 (PCB->Filename, -1, NULL, NULL, NULL); 00266 00267 secondary_text = PCB->Changed ? _("Do you want to drop your changes and reload the file?") : 00268 _("Do you want to reload the file?"); 00269 00270 markup = g_markup_printf_escaped (_("<b>The file %s has changed on disk</b>\n\n%s"), 00271 file_path_utf8, secondary_text); 00272 g_free (file_path_utf8); 00273 00274 content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (ghidgui->info_bar)); 00275 00276 icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, 00277 GTK_ICON_SIZE_DIALOG); 00278 gtk_box_pack_start (GTK_BOX (content_area), 00279 icon, FALSE, FALSE, 0); 00280 00281 label = gtk_label_new (""); 00282 gtk_box_pack_start (GTK_BOX (content_area), 00283 label, TRUE, TRUE, 6); 00284 00285 gtk_label_set_use_markup (GTK_LABEL (label), TRUE); 00286 gtk_label_set_markup (GTK_LABEL (label), markup); 00287 g_free (markup); 00288 00289 gtk_misc_set_alignment (GTK_MISC (label), 0., 0.5); 00290 00291 gtk_widget_show_all (ghidgui->info_bar); 00292 } 00293 00294 static bool 00295 check_externally_modified (void) 00296 { 00297 GFile *file; 00298 GFileInfo *info; 00299 GTimeVal timeval; 00300 00301 /* Treat zero time as a flag to indicate we've not got an mtime yet */ 00302 if (PCB->Filename == NULL || 00303 (ghidgui->our_mtime.tv_sec == 0 && 00304 ghidgui->our_mtime.tv_usec == 0)) 00305 return false; 00306 00307 file = g_file_new_for_path (PCB->Filename); 00308 info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED, 00309 G_FILE_QUERY_INFO_NONE, NULL, NULL); 00310 g_object_unref (file); 00311 00312 if (info == NULL || 00313 !g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED)) 00314 return false; 00315 00316 g_file_info_get_modification_time (info, &timeval); //&ghidgui->last_seen_mtime); 00317 g_object_unref (info); 00318 00319 /* Ignore when the file on disk is the same age as when we last looked */ 00320 if (timeval.tv_sec == ghidgui->last_seen_mtime.tv_sec && 00321 timeval.tv_usec == ghidgui->last_seen_mtime.tv_usec) 00322 return false; 00323 00324 ghidgui->last_seen_mtime = timeval; 00325 00326 return (ghidgui->last_seen_mtime.tv_sec > ghidgui->our_mtime.tv_sec) || 00327 (ghidgui->last_seen_mtime.tv_sec == ghidgui->our_mtime.tv_sec && 00328 ghidgui->last_seen_mtime.tv_usec > ghidgui->our_mtime.tv_usec); 00329 } 00330 00331 static gboolean 00332 top_window_enter_cb (GtkWidget *widget, GdkEvent *event, GHidPort *port) 00333 { 00334 if (check_externally_modified ()) 00335 show_file_modified_externally_prompt (); 00336 00337 return FALSE; 00338 } 00339 00355 static void 00356 ghid_menu_cb (GtkAction *action, const Resource *node) 00357 { 00358 int i; 00359 00360 if (action == NULL || node == NULL) 00361 return; 00362 00363 for (i = 1; i < node->c; i++) 00364 if (resource_type (node->v[i]) == 10) 00365 { 00366 #ifdef DEBUG_MENUS 00367 printf (" %s\n", node->v[i].value); 00368 #endif 00369 hid_parse_actions (node->v[i].value); 00370 } 00371 00372 /* Sync gui widgets with pcb state */ 00373 ghid_update_toggle_flags (); 00374 ghid_mode_buttons_update (); 00375 00376 /* Sync gui status display with pcb state */ 00377 AdjustAttachedObjects (); 00378 ghid_invalidate_all (); 00379 ghid_window_set_name_label (PCB->Name); 00380 ghid_set_status_line_label (); 00381 } 00382 00387 void ghid_hotkey_cb (int which) 00388 { 00389 if (ghid_hotkey_actions[which].action != NULL) 00390 ghid_menu_cb (ghid_hotkey_actions[which].action, 00391 (gpointer) ghid_hotkey_actions[which].node); 00392 } 00393 00394 static void 00395 update_board_mtime_from_disk (void) 00396 { 00397 GFile *file; 00398 GFileInfo *info; 00399 00400 ghidgui->our_mtime.tv_sec = 0; 00401 ghidgui->our_mtime.tv_usec = 0; 00402 ghidgui->last_seen_mtime = ghidgui->our_mtime; 00403 00404 if (PCB->Filename == NULL) 00405 return; 00406 00407 file = g_file_new_for_path (PCB->Filename); 00408 info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED, 00409 G_FILE_QUERY_INFO_NONE, NULL, NULL); 00410 g_object_unref (file); 00411 00412 if (info == NULL || 00413 !g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED)) 00414 return; 00415 00416 g_file_info_get_modification_time (info, &ghidgui->our_mtime); 00417 g_object_unref (info); 00418 00419 ghidgui->last_seen_mtime = ghidgui->our_mtime; 00420 } 00421 00426 void 00427 ghid_sync_with_new_layout (void) 00428 { 00429 pcb_use_route_style (&PCB->RouteStyle[0]); 00430 ghid_route_style_selector_select_style 00431 (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector), 00432 &PCB->RouteStyle[0]); 00433 00434 ghid_config_handle_units_changed (); 00435 00436 ghid_window_set_name_label (PCB->Name); 00437 ghid_set_status_line_label (); 00438 close_file_modified_externally_prompt (); 00439 update_board_mtime_from_disk (); 00440 } 00441 00442 void 00443 ghid_notify_save_pcb (const char *filename, bool done) 00444 { 00445 /* Do nothing if it is not the active PCB file that is being saved. 00446 */ 00447 if (PCB->Filename == NULL || strcmp (filename, PCB->Filename) != 0) 00448 return; 00449 00450 if (done) 00451 update_board_mtime_from_disk (); 00452 } 00453 00454 void 00455 ghid_notify_filename_changed (void) 00456 { 00457 /* Pick up the mtime of the new PCB file */ 00458 update_board_mtime_from_disk (); 00459 } 00460 00468 void 00469 layer_process (gchar **color_string, char **text, int *set, int i) 00470 { 00471 int tmp; 00472 char *tmps; 00473 gchar *tmpc; 00474 00475 /* cheap hack to let users pass in NULL for either text or set if 00476 * they don't care about the result 00477 */ 00478 00479 if (color_string == NULL) 00480 color_string = &tmpc; 00481 00482 if (text == NULL) 00483 text = &tmps; 00484 00485 if (set == NULL) 00486 set = &tmp; 00487 00488 switch (i) 00489 { 00490 case LAYER_BUTTON_SILK: 00491 *color_string = Settings.ElementColor; 00492 if (Settings.ShowBottomSide) 00493 *text = (char *)UNKNOWN (PCB->Data->Layer[bottom_silk_layer].Name); 00494 else 00495 *text = (char *)UNKNOWN (PCB->Data->Layer[top_silk_layer].Name); 00496 *set = PCB->ElementOn; 00497 break; 00498 case LAYER_BUTTON_RATS: 00499 *color_string = Settings.RatColor; 00500 *text = _( "rat lines"); 00501 *set = PCB->RatOn; 00502 break; 00503 case LAYER_BUTTON_PINS: 00504 *color_string = Settings.PinColor; 00505 *text = _( "pins/pads"); 00506 *set = PCB->PinOn; 00507 break; 00508 case LAYER_BUTTON_VIAS: 00509 *color_string = Settings.ViaColor; 00510 *text = _( "vias"); 00511 *set = PCB->ViaOn; 00512 break; 00513 case LAYER_BUTTON_FARSIDE: 00514 *color_string = Settings.InvisibleObjectsColor; 00515 *text = _( "far side"); 00516 *set = PCB->InvisibleObjectsOn; 00517 break; 00518 case LAYER_BUTTON_MASK: 00519 *color_string = Settings.MaskColor; 00520 *text = _( "solder mask"); 00521 *set = TEST_FLAG (SHOWMASKFLAG, PCB); 00522 break; 00523 default: /* layers */ 00524 *color_string = Settings.LayerColor[i]; 00525 *text = (char *)UNKNOWN (PCB->Data->Layer[i].Name); 00526 *set = PCB->Data->Layer[i].On; 00527 break; 00528 } 00529 } 00530 00534 static void 00535 layer_selector_select_callback (GHidLayerSelector *ls, int layer, gpointer d) 00536 { 00537 ignore_layer_update = true; 00538 /* Select Layer */ 00539 PCB->SilkActive = (layer == LAYER_BUTTON_SILK); 00540 PCB->RatDraw = (layer == LAYER_BUTTON_RATS); 00541 if (layer == LAYER_BUTTON_SILK) 00542 { 00543 PCB->ElementOn = true; 00544 hid_action ("LayersChanged"); 00545 } 00546 else if (layer == LAYER_BUTTON_RATS) 00547 { 00548 PCB->RatOn = true; 00549 hid_action ("LayersChanged"); 00550 } 00551 else if (layer < max_copper_layer) 00552 ChangeGroupVisibility (layer, TRUE, true); 00553 00554 ignore_layer_update = false; 00555 00556 ghid_invalidate_all (); 00557 } 00558 00562 static void 00563 layer_selector_rename_callback (GHidLayerSelector *ls, 00564 int layer_id, 00565 char *new_name, 00566 void *userdata) 00567 { 00568 LayerType *layer = LAYER_PTR (layer_id); 00569 00570 /* Check for a legal layer name - for now, allow anything non-empty */ 00571 if (new_name[0] == '\0') 00572 return; 00573 00574 /* Don't bother if the name is identical to the current one */ 00575 if (strcmp (layer->Name, new_name) == 0) 00576 return; 00577 00578 free (layer->Name); 00579 layer->Name = strdup (new_name); 00580 ghid_layer_buttons_update (); 00581 if (!PCB->Changed) 00582 { 00583 SetChangedFlag (true); 00584 ghid_window_set_name_label (PCB->Name); 00585 } 00586 } 00587 00591 static void 00592 layer_selector_toggle_callback (GHidLayerSelector *ls, int layer, gpointer d) 00593 { 00594 gboolean redraw = FALSE; 00595 gboolean active; 00596 layer_process (NULL, NULL, &active, layer); 00597 00598 active = !active; 00599 ignore_layer_update = true; 00600 switch (layer) 00601 { 00602 case LAYER_BUTTON_SILK: 00603 PCB->ElementOn = active; 00604 PCB->Data->SILKLAYER.On = PCB->ElementOn; 00605 PCB->Data->BACKSILKLAYER.On = PCB->ElementOn; 00606 redraw = 1; 00607 break; 00608 case LAYER_BUTTON_RATS: 00609 PCB->RatOn = active; 00610 redraw = 1; 00611 break; 00612 case LAYER_BUTTON_PINS: 00613 PCB->PinOn = active; 00614 redraw |= (PCB->Data->ElementN != 0); 00615 break; 00616 case LAYER_BUTTON_VIAS: 00617 PCB->ViaOn = active; 00618 redraw |= (PCB->Data->ViaN != 0); 00619 break; 00620 case LAYER_BUTTON_FARSIDE: 00621 PCB->InvisibleObjectsOn = active; 00622 PCB->Data->BACKSILKLAYER.On = (active && PCB->ElementOn); 00623 redraw = TRUE; 00624 break; 00625 case LAYER_BUTTON_MASK: 00626 if (active) 00627 SET_FLAG (SHOWMASKFLAG, PCB); 00628 else 00629 CLEAR_FLAG (SHOWMASKFLAG, PCB); 00630 redraw = TRUE; 00631 break; 00632 default: 00633 /* Flip the visibility */ 00634 ChangeGroupVisibility (layer, active, false); 00635 redraw = TRUE; 00636 break; 00637 } 00638 00639 /* Select the next visible layer. (If there is none, this will 00640 * select the currently-selected layer, triggering the selection 00641 * callback, which will turn the visibility on.) This way we 00642 * will never have an invisible layer selected. 00643 */ 00644 if (!active) 00645 ghid_layer_selector_select_next_visible (ls); 00646 00647 ignore_layer_update = false; 00648 00649 if (redraw) 00650 ghid_invalidate_all(); 00651 } 00652 00656 void 00657 ghid_install_accel_groups (GtkWindow *window, GhidGui *gui) 00658 { 00659 gtk_window_add_accel_group 00660 (window, ghid_main_menu_get_accel_group 00661 (GHID_MAIN_MENU (gui->menu_bar))); 00662 gtk_window_add_accel_group 00663 (window, ghid_layer_selector_get_accel_group 00664 (GHID_LAYER_SELECTOR (gui->layer_selector))); 00665 gtk_window_add_accel_group 00666 (window, ghid_route_style_selector_get_accel_group 00667 (GHID_ROUTE_STYLE_SELECTOR (gui->route_style_selector))); 00668 } 00669 00673 void 00674 ghid_remove_accel_groups (GtkWindow *window, GhidGui *gui) 00675 { 00676 gtk_window_remove_accel_group 00677 (window, ghid_main_menu_get_accel_group 00678 (GHID_MAIN_MENU (gui->menu_bar))); 00679 gtk_window_remove_accel_group 00680 (window, ghid_layer_selector_get_accel_group 00681 (GHID_LAYER_SELECTOR (gui->layer_selector))); 00682 gtk_window_remove_accel_group 00683 (window, ghid_route_style_selector_get_accel_group 00684 (GHID_ROUTE_STYLE_SELECTOR (gui->route_style_selector))); 00685 } 00686 00691 void 00692 ghid_window_set_name_label (gchar * name) 00693 { 00694 gchar *str; 00695 gchar *filename; 00696 00697 /* FIXME -- should this happen? It does... */ 00698 /* This happens if we're calling an exporter from the command line */ 00699 if (ghidgui == NULL) 00700 return; 00701 00702 dup_string (&(ghidgui->name_label_string), name); 00703 if (!ghidgui->name_label_string || !*ghidgui->name_label_string) 00704 ghidgui->name_label_string = g_strdup (_("Unnamed")); 00705 00706 if (!PCB->Filename || !*PCB->Filename) 00707 filename = g_strdup(_("Unsaved.pcb")); 00708 else 00709 filename = g_strdup(PCB->Filename); 00710 00711 str = g_strdup_printf ("%s%s (%s) - PCB", PCB->Changed ? "*": "", 00712 ghidgui->name_label_string, filename); 00713 gtk_window_set_title (GTK_WINDOW (gport->top_window), str); 00714 g_free (str); 00715 g_free (filename); 00716 } 00717 00718 static void 00719 grid_units_button_cb (GtkWidget * widget, gpointer data) 00720 { 00721 /* Button only toggles between mm and mil */ 00722 if (Settings.grid_unit == get_unit_struct ("mm")) 00723 hid_actionl ("SetUnits", "mil", NULL); 00724 else 00725 hid_actionl ("SetUnits", "mm", NULL); 00726 } 00727 00733 static void 00734 absolute_label_size_req_cb (GtkWidget * widget, 00735 GtkRequisition *req, gpointer data) 00736 { 00737 00738 static gint w = 0; 00739 if (req->width > w) 00740 w = req->width; 00741 else 00742 req->width = w; 00743 } 00744 00745 static void 00746 relative_label_size_req_cb (GtkWidget * widget, 00747 GtkRequisition *req, gpointer data) 00748 { 00749 00750 static gint w = 0; 00751 if (req->width > w) 00752 w = req->width; 00753 else 00754 req->width = w; 00755 } 00756 00757 static void 00758 make_cursor_position_labels (GtkWidget * hbox, GHidPort * port) 00759 { 00760 GtkWidget *frame, *label; 00761 00762 /* The grid units button next to the cursor position labels. 00763 */ 00764 ghidgui->grid_units_button = gtk_button_new (); 00765 label = gtk_label_new (""); 00766 gtk_label_set_markup (GTK_LABEL (label), 00767 Settings.grid_unit->in_suffix); 00768 ghidgui->grid_units_label = label; 00769 gtk_label_set_use_markup (GTK_LABEL (label), TRUE); 00770 gtk_container_add (GTK_CONTAINER (ghidgui->grid_units_button), label); 00771 gtk_box_pack_end (GTK_BOX (hbox), ghidgui->grid_units_button, FALSE, TRUE, 0); 00772 g_signal_connect (ghidgui->grid_units_button, "clicked", 00773 G_CALLBACK (grid_units_button_cb), NULL); 00774 00775 /* The absolute cursor position label 00776 */ 00777 frame = gtk_frame_new (NULL); 00778 gtk_box_pack_end (GTK_BOX (hbox), frame, FALSE, TRUE, 0); 00779 gtk_container_set_border_width (GTK_CONTAINER (frame), 0); 00780 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT); 00781 00782 label = gtk_label_new (""); 00783 gtk_container_add (GTK_CONTAINER (frame), label); 00784 ghidgui->cursor_position_absolute_label = label; 00785 g_signal_connect (G_OBJECT (label), "size-request", 00786 G_CALLBACK (absolute_label_size_req_cb), NULL); 00787 00788 00789 /* The relative cursor position label 00790 */ 00791 frame = gtk_frame_new (NULL); 00792 gtk_box_pack_end (GTK_BOX (hbox), frame, FALSE, TRUE, 0); 00793 gtk_container_set_border_width (GTK_CONTAINER (frame), 0); 00794 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT); 00795 label = gtk_label_new (" __.__ __.__ "); 00796 gtk_container_add (GTK_CONTAINER (frame), label); 00797 ghidgui->cursor_position_relative_label = label; 00798 g_signal_connect (G_OBJECT (label), "size-request", 00799 G_CALLBACK (relative_label_size_req_cb), NULL); 00800 00801 } 00802 00806 static void 00807 make_virtual_layer_buttons (GtkWidget *layer_selector) 00808 { 00809 GHidLayerSelector *layersel = GHID_LAYER_SELECTOR (layer_selector); 00810 gchar *text; 00811 gchar *color_string; 00812 gboolean active; 00813 00814 layer_process (&color_string, &text, &active, LAYER_BUTTON_SILK); 00815 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_SILK, 00816 text, color_string, active, TRUE, FALSE); 00817 layer_process (&color_string, &text, &active, LAYER_BUTTON_RATS); 00818 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_RATS, 00819 text, color_string, active, TRUE, FALSE); 00820 layer_process (&color_string, &text, &active, LAYER_BUTTON_PINS); 00821 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_PINS, 00822 text, color_string, active, FALSE, FALSE); 00823 layer_process (&color_string, &text, &active, LAYER_BUTTON_VIAS); 00824 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_VIAS, 00825 text, color_string, active, FALSE, FALSE); 00826 layer_process (&color_string, &text, &active, LAYER_BUTTON_FARSIDE); 00827 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_FARSIDE, 00828 text, color_string, active, FALSE, FALSE); 00829 layer_process (&color_string, &text, &active, LAYER_BUTTON_MASK); 00830 ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_MASK, 00831 text, color_string, active, FALSE, FALSE); 00832 } 00833 00837 const gchar * 00838 get_layer_color (gint layer) 00839 { 00840 gchar *rv; 00841 layer_process (&rv, NULL, NULL, layer); 00842 return rv; 00843 } 00844 00848 void 00849 ghid_layer_buttons_color_update (void) 00850 { 00851 ghid_layer_selector_update_colors 00852 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), get_layer_color); 00853 pcb_colors_from_settings (PCB); 00854 } 00855 00859 static void 00860 make_layer_buttons (GtkWidget *layersel) 00861 { 00862 gint i; 00863 gchar *text; 00864 gchar *color_string; 00865 gboolean active = TRUE; 00866 00867 for (i = 0; i < max_copper_layer; ++i) 00868 { 00869 layer_process (&color_string, &text, &active, i); 00870 ghid_layer_selector_add_layer (GHID_LAYER_SELECTOR (layersel), i, 00871 text, color_string, active, TRUE, TRUE); 00872 } 00873 } 00874 00875 00879 gboolean 00880 get_layer_delete (gint layer) 00881 { 00882 return layer >= max_copper_layer; 00883 } 00884 00891 void 00892 ghid_layer_buttons_update (void) 00893 { 00894 gint layer; 00895 00896 if (ignore_layer_update) 00897 return; 00898 00899 ghid_layer_selector_delete_layers 00900 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), 00901 get_layer_delete); 00902 make_layer_buttons (ghidgui->layer_selector); 00903 make_virtual_layer_buttons (ghidgui->layer_selector); 00904 ghid_main_menu_install_layer_selector 00905 (GHID_MAIN_MENU (ghidgui->menu_bar), 00906 GHID_LAYER_SELECTOR (ghidgui->layer_selector)); 00907 00908 /* Sync selected layer with PCB's state */ 00909 if (PCB->RatDraw) 00910 layer = LAYER_BUTTON_RATS; 00911 else if (PCB->SilkActive) 00912 layer = LAYER_BUTTON_SILK; 00913 else 00914 layer = LayerStack[0]; 00915 00916 ghid_layer_selector_select_layer 00917 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), layer); 00918 } 00919 00923 static void 00924 route_styles_edited_cb (GHidRouteStyleSelector *rss, gboolean save, 00925 gpointer data) 00926 { 00927 if (save) 00928 { 00929 g_free (Settings.Routes); 00930 Settings.Routes = make_route_string (PCB->RouteStyle, NUM_STYLES); 00931 ghidgui->config_modified = TRUE; 00932 ghid_config_files_write (); 00933 } 00934 ghid_main_menu_install_route_style_selector 00935 (GHID_MAIN_MENU (ghidgui->menu_bar), 00936 GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector)); 00937 } 00938 00942 static void 00943 route_style_changed_cb (GHidRouteStyleSelector *rss, RouteStyleType *rst, 00944 gpointer data) 00945 { 00946 pcb_use_route_style (rst); 00947 ghid_set_status_line_label(); 00948 } 00949 00953 void 00954 make_route_style_buttons (GHidRouteStyleSelector *rss) 00955 { 00956 int i; 00957 for (i = 0; i < NUM_STYLES; ++i) 00958 ghid_route_style_selector_add_route_style (rss, &PCB->RouteStyle[i]); 00959 g_signal_connect (G_OBJECT (rss), "select_style", 00960 G_CALLBACK (route_style_changed_cb), NULL); 00961 g_signal_connect (G_OBJECT (rss), "style_edited", 00962 G_CALLBACK (route_styles_edited_cb), NULL); 00963 ghid_main_menu_install_route_style_selector 00964 (GHID_MAIN_MENU (ghidgui->menu_bar), 00965 GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector)); 00966 } 00967 00971 typedef struct 00972 { 00973 GtkWidget *button; 00974 GtkWidget *toolbar_button; 00975 guint button_cb_id; 00976 guint toolbar_button_cb_id; 00977 gchar *name; 00978 gint mode; 00979 gchar **xpm; 00980 gchar *tooltip; 00981 } 00982 ModeButton; 00983 00984 00985 static ModeButton mode_buttons[] = { 00986 {NULL, NULL, 0, 0, N_("via"), VIA_MODE, via, 00987 N_("create vias with <select mouse button>")}, 00988 {NULL, NULL, 0, 0, N_("line"), LINE_MODE, line, 00989 N_("create a line segment, toggle draw modes with '/' or '.'")}, 00990 {NULL, NULL, 0, 0, N_("arc"), ARC_MODE, arc, 00991 N_("create an arc segment")}, 00992 {NULL, NULL, 0, 0, N_("text"), TEXT_MODE, text, 00993 N_("create a text")}, 00994 {NULL, NULL, 0, 0, N_("rectangle"), RECTANGLE_MODE, rect, 00995 N_("create a filled rectangle")}, 00996 {NULL, NULL, 0, 0, N_("polygon"), POLYGON_MODE, poly, 00997 N_("create a polygon, <shift>-P for closing the polygon")}, 00998 {NULL, NULL, 0, 0, N_("polygonhole"), POLYGONHOLE_MODE, polyhole, 00999 N_("create a hole into an existing polygon")}, 01000 {NULL, NULL, 0, 0, N_("buffer"), PASTEBUFFER_MODE, buf, 01001 N_("paste the selection from buffer into the layout")}, 01002 {NULL, NULL, 0, 0, N_("remove"), REMOVE_MODE, del, 01003 N_("remove objects under the cursor")}, 01004 {NULL, NULL, 0, 0, N_("rotate"), ROTATE_MODE, rot, 01005 N_("rotate a selection or object CCW, hold the <shift> key to rotate CW")}, 01006 {NULL, NULL, 0, 0, N_("insertPoint"), INSERTPOINT_MODE, ins, 01007 N_("add points into existing lines and polygons")}, 01008 {NULL, NULL, 0, 0, N_("thermal"), THERMAL_MODE, thrm, 01009 N_("create thermals with <select mouse button>, toggle thermal style with <Shift> <select mouse button>")}, 01010 {NULL, NULL, 0, 0, N_("select"), ARROW_MODE, sel, 01011 N_("select, deselect or move objects or selections")}, 01012 {NULL, NULL, 0, 0, N_("lock"), LOCK_MODE, lock, 01013 N_("lock or unlock an object")} 01014 }; 01015 01016 static gint n_mode_buttons = G_N_ELEMENTS (mode_buttons); 01017 01018 static void 01019 do_set_mode (int mode) 01020 { 01021 SetMode (mode); 01022 ghid_mode_cursor (mode); 01023 ghidgui->settings_mode = mode; 01024 } 01025 01026 static void 01027 mode_toolbar_button_toggled_cb (GtkToggleButton *button, ModeButton * mb) 01028 { 01029 gboolean active = gtk_toggle_button_get_active (button); 01030 01031 if (mb->button != NULL) 01032 { 01033 g_signal_handler_block (mb->button, mb->button_cb_id); 01034 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->button), active); 01035 g_signal_handler_unblock (mb->button, mb->button_cb_id); 01036 } 01037 01038 if (active) 01039 do_set_mode (mb->mode); 01040 } 01041 01042 static void 01043 mode_button_toggled_cb (GtkWidget * widget, ModeButton * mb) 01044 { 01045 gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); 01046 01047 if (mb->toolbar_button != NULL) 01048 { 01049 g_signal_handler_block (mb->toolbar_button, mb->toolbar_button_cb_id); 01050 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->toolbar_button), active); 01051 g_signal_handler_unblock (mb->toolbar_button, mb->toolbar_button_cb_id); 01052 } 01053 01054 if (active) 01055 do_set_mode (mb->mode); 01056 } 01057 01058 void 01059 ghid_mode_buttons_update (void) 01060 { 01061 ModeButton *mb; 01062 gint i; 01063 01064 for (i = 0; i < n_mode_buttons; ++i) 01065 { 01066 mb = &mode_buttons[i]; 01067 if (Settings.Mode == mb->mode) 01068 { 01069 g_signal_handler_block (mb->button, mb->button_cb_id); 01070 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->button), TRUE); 01071 g_signal_handler_unblock (mb->button, mb->button_cb_id); 01072 01073 g_signal_handler_block (mb->toolbar_button, mb->toolbar_button_cb_id); 01074 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->toolbar_button), TRUE); 01075 g_signal_handler_unblock (mb->toolbar_button, mb->toolbar_button_cb_id); 01076 break; 01077 } 01078 } 01079 } 01080 01081 void 01082 ghid_pack_mode_buttons (void) 01083 { 01084 if (ghidgui->compact_vertical) 01085 { 01086 gtk_widget_hide (ghidgui->mode_buttons_frame); 01087 gtk_widget_show_all (ghidgui->mode_toolbar); 01088 } 01089 else 01090 { 01091 gtk_widget_hide (ghidgui->mode_toolbar); 01092 gtk_widget_show_all (ghidgui->mode_buttons_frame); 01093 } 01094 } 01095 01096 static void 01097 make_mode_buttons_and_toolbar (GtkWidget **mode_frame, 01098 GtkWidget **mode_toolbar) 01099 { 01100 GtkToolItem *tool_item; 01101 GtkWidget *vbox, *hbox = NULL; 01102 GtkWidget *image; 01103 GdkPixbuf *pixbuf; 01104 GSList *group = NULL; 01105 GSList *toolbar_group = NULL; 01106 ModeButton *mb; 01107 int i; 01108 01109 *mode_toolbar = gtk_toolbar_new (); 01110 01111 *mode_frame = gtk_frame_new (NULL); 01112 vbox = gtk_vbox_new (FALSE, 0); 01113 gtk_container_add (GTK_CONTAINER (*mode_frame), vbox); 01114 01115 for (i = 0; i < n_mode_buttons; ++i) 01116 { 01117 mb = &mode_buttons[i]; 01118 01119 /* Create tool button for mode frame */ 01120 mb->button = gtk_radio_button_new (group); 01121 gtk_widget_set_tooltip_text (mb->button, _(mb->tooltip)); 01122 gtk_widget_set_name (mb->button, (mb->name)); 01123 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (mb->button)); 01124 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (mb->button), FALSE); 01125 01126 /* Create tool button for toolbar */ 01127 mb->toolbar_button = gtk_radio_button_new (toolbar_group); 01128 gtk_widget_set_tooltip_text (mb->toolbar_button, _(mb->tooltip)); 01129 gtk_widget_set_name (mb->toolbar_button, (mb->name)); 01130 toolbar_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (mb->toolbar_button)); 01131 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (mb->toolbar_button), FALSE); 01132 01133 /* Pack mode-frame button into the frame */ 01134 if ((i % ghidgui->n_mode_button_columns) == 0) 01135 { 01136 hbox = gtk_hbox_new (FALSE, 0); 01137 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); 01138 } 01139 gtk_box_pack_start (GTK_BOX (hbox), mb->button, FALSE, FALSE, 0); 01140 01141 /* Create a container for the toolbar button and add that */ 01142 tool_item = gtk_tool_item_new (); 01143 gtk_container_add (GTK_CONTAINER (tool_item), mb->toolbar_button); 01144 gtk_toolbar_insert (GTK_TOOLBAR (*mode_toolbar), tool_item, -1); 01145 01146 /* Load the image for the button, create GtkImage widgets for both 01147 * the grid button and the toolbar button, then pack into the buttons 01148 */ 01149 pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **) mb->xpm); 01150 image = gtk_image_new_from_pixbuf (pixbuf); 01151 gtk_container_add (GTK_CONTAINER (mb->button), image); 01152 image = gtk_image_new_from_pixbuf (pixbuf); 01153 gtk_container_add (GTK_CONTAINER (mb->toolbar_button), image); 01154 g_object_unref (pixbuf); 01155 01156 if (strcmp (mb->name, "select") == 0) 01157 { 01158 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->button), TRUE); 01159 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->toolbar_button), TRUE); 01160 } 01161 01162 mb->button_cb_id = 01163 g_signal_connect (mb->button, "toggled", 01164 G_CALLBACK (mode_button_toggled_cb), mb); 01165 mb->toolbar_button_cb_id = 01166 g_signal_connect (mb->toolbar_button, "toggled", 01167 G_CALLBACK (mode_toolbar_button_toggled_cb), mb); 01168 } 01169 } 01170 01171 01172 /* 01173 * --------------------------------------------------------------- 01174 * Top window 01175 * --------------------------------------------------------------- 01176 */ 01177 01178 static gint 01179 delete_chart_cb (GtkWidget * widget, GdkEvent * event, GHidPort * port) 01180 { 01181 ghid_config_files_write (); 01182 hid_action ("Quit"); 01183 01184 /* 01185 * Return TRUE to keep our app running. A FALSE here would let the 01186 * delete signal continue on and kill our program. 01187 */ 01188 return TRUE; 01189 } 01190 01191 static void 01192 destroy_chart_cb (GtkWidget * widget, GHidPort * port) 01193 { 01194 ghid_shutdown_renderer (port); 01195 gtk_main_quit (); 01196 } 01197 01198 static void 01199 get_widget_styles (GtkStyle **menu_bar_style, 01200 GtkStyle **tool_button_style, 01201 GtkStyle **tool_button_label_style) 01202 { 01203 GtkWidget *tool_button; 01204 GtkWidget *tool_button_label; 01205 GtkToolItem *tool_item; 01206 01207 /* Build a tool item to extract the theme's styling for a toolbar button with text */ 01208 tool_item = gtk_tool_item_new (); 01209 gtk_toolbar_insert (GTK_TOOLBAR (ghidgui->mode_toolbar), tool_item, 0); 01210 tool_button = gtk_button_new (); 01211 gtk_container_add (GTK_CONTAINER (tool_item), tool_button); 01212 tool_button_label = gtk_label_new (""); 01213 gtk_container_add (GTK_CONTAINER (tool_button), tool_button_label); 01214 01215 /* Grab the various styles we need */ 01216 gtk_widget_ensure_style (ghidgui->menu_bar); 01217 *menu_bar_style = gtk_widget_get_style (ghidgui->menu_bar); 01218 01219 gtk_widget_ensure_style (tool_button); 01220 *tool_button_style = gtk_widget_get_style (tool_button); 01221 01222 gtk_widget_ensure_style (tool_button_label); 01223 *tool_button_label_style = gtk_widget_get_style (tool_button_label); 01224 01225 gtk_widget_destroy (GTK_WIDGET (tool_item)); 01226 } 01227 01228 static void 01229 do_fix_topbar_theming (void) 01230 { 01231 GtkWidget *rel_pos_frame; 01232 GtkWidget *abs_pos_frame; 01233 GtkStyle *menu_bar_style; 01234 GtkStyle *tool_button_style; 01235 GtkStyle *tool_button_label_style; 01236 01237 get_widget_styles (&menu_bar_style, 01238 &tool_button_style, 01239 &tool_button_label_style); 01240 01241 /* Style the top bar background as if it were all a menu bar */ 01242 gtk_widget_set_style (ghidgui->top_bar_background, menu_bar_style); 01243 01244 /* Style the cursor position labels using the menu bar style as well. 01245 * If this turns out to cause problems with certain gtk themes, we may 01246 * need to grab the GtkStyle associated with an actual menu item to 01247 * get a text color to render with. 01248 */ 01249 gtk_widget_set_style (ghidgui->cursor_position_relative_label, menu_bar_style); 01250 gtk_widget_set_style (ghidgui->cursor_position_absolute_label, menu_bar_style); 01251 01252 /* Style the units button as if it were a toolbar button - hopefully 01253 * this isn't too ugly sitting on a background themed as a menu bar. 01254 * It is unlikely any theme defines colours for a GtkButton sitting on 01255 * a menu bar. 01256 */ 01257 rel_pos_frame = gtk_widget_get_parent (ghidgui->cursor_position_relative_label); 01258 abs_pos_frame = gtk_widget_get_parent (ghidgui->cursor_position_absolute_label); 01259 gtk_widget_set_style (rel_pos_frame, menu_bar_style); 01260 gtk_widget_set_style (abs_pos_frame, menu_bar_style); 01261 gtk_widget_set_style (ghidgui->grid_units_button, tool_button_style); 01262 gtk_widget_set_style (ghidgui->grid_units_label, tool_button_label_style); 01263 } 01264 01273 static void 01274 fix_topbar_theming (void) 01275 { 01276 GtkSettings *settings; 01277 01278 do_fix_topbar_theming (); 01279 01280 settings = gtk_widget_get_settings (ghidgui->top_bar_background); 01281 g_signal_connect (settings, "notify::gtk-theme-name", 01282 G_CALLBACK (do_fix_topbar_theming), NULL); 01283 g_signal_connect (settings, "notify::gtk-font-name", 01284 G_CALLBACK (do_fix_topbar_theming), NULL); 01285 } 01286 01292 static void 01293 ghid_build_pcb_top_window (void) 01294 { 01295 GtkWidget *window; 01296 GtkWidget *vbox_main, *hbox_middle, *hbox; 01297 GtkWidget *vbox, *frame; 01298 GtkWidget *label; 01299 /* FIXME: IFDEF HACK */ 01300 #ifdef ENABLE_GL 01301 GtkWidget *trackball; 01302 #endif 01303 GHidPort *port = &ghid_port; 01304 GtkWidget *scrolled; 01305 01306 window = gport->top_window; 01307 01308 vbox_main = gtk_vbox_new (FALSE, 0); 01309 gtk_container_add (GTK_CONTAINER (window), vbox_main); 01310 01311 /* -- Top control bar */ 01312 ghidgui->top_bar_background = gtk_event_box_new (); 01313 gtk_box_pack_start (GTK_BOX (vbox_main), 01314 ghidgui->top_bar_background, FALSE, FALSE, 0); 01315 01316 ghidgui->top_hbox = gtk_hbox_new (FALSE, 0); 01317 gtk_container_add (GTK_CONTAINER (ghidgui->top_bar_background), 01318 ghidgui->top_hbox); 01319 01320 /* 01321 * menu_hbox will be made insensitive when the gui needs 01322 * a modal button GetLocation button press. 01323 */ 01324 ghidgui->menu_hbox = gtk_hbox_new (FALSE, 0); 01325 gtk_box_pack_start (GTK_BOX (ghidgui->top_hbox), ghidgui->menu_hbox, 01326 FALSE, FALSE, 0); 01327 01328 ghidgui->menubar_toolbar_vbox = gtk_vbox_new (FALSE, 0); 01329 gtk_box_pack_start (GTK_BOX (ghidgui->menu_hbox), 01330 ghidgui->menubar_toolbar_vbox, FALSE, FALSE, 0); 01331 01332 /* Build layer menus */ 01333 ghidgui->layer_selector = ghid_layer_selector_new (); 01334 make_layer_buttons (ghidgui->layer_selector); 01335 make_virtual_layer_buttons (ghidgui->layer_selector); 01336 g_signal_connect (G_OBJECT (ghidgui->layer_selector), "select-layer", 01337 G_CALLBACK (layer_selector_select_callback), 01338 NULL); 01339 g_signal_connect (G_OBJECT (ghidgui->layer_selector), "toggle-layer", 01340 G_CALLBACK (layer_selector_toggle_callback), 01341 NULL); 01342 g_signal_connect (G_OBJECT (ghidgui->layer_selector), "rename-layer", 01343 G_CALLBACK (layer_selector_rename_callback), 01344 NULL); 01345 /* Build main menu */ 01346 ghidgui->menu_bar = ghid_load_menus (); 01347 gtk_box_pack_start (GTK_BOX (ghidgui->menubar_toolbar_vbox), 01348 ghidgui->menu_bar, FALSE, FALSE, 0); 01349 01350 make_mode_buttons_and_toolbar (&ghidgui->mode_buttons_frame, 01351 &ghidgui->mode_toolbar); 01352 gtk_box_pack_start (GTK_BOX (ghidgui->menubar_toolbar_vbox), 01353 ghidgui->mode_toolbar, FALSE, FALSE, 0); 01354 01355 01356 ghidgui->position_hbox = gtk_hbox_new (FALSE, 0); 01357 gtk_box_pack_end (GTK_BOX(ghidgui->top_hbox), 01358 ghidgui->position_hbox, TRUE, TRUE, 0); 01359 01360 make_cursor_position_labels (ghidgui->position_hbox, port); 01361 01362 hbox_middle = gtk_hbox_new (FALSE, 0); 01363 gtk_box_pack_start (GTK_BOX (vbox_main), hbox_middle, TRUE, TRUE, 0); 01364 01365 fix_topbar_theming (); /* Must be called after toolbar is created */ 01366 01367 /* -- Left control bar */ 01368 /* 01369 * This box will be made insensitive when the gui needs 01370 * a modal button GetLocation button press. 01371 */ 01372 ghidgui->left_toolbar = gtk_vbox_new (FALSE, 0); 01373 gtk_box_pack_start (GTK_BOX (hbox_middle), 01374 ghidgui->left_toolbar, FALSE, FALSE, 0); 01375 01376 vbox = ghid_scrolled_vbox (ghidgui->left_toolbar, &scrolled, 01377 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); 01378 gtk_box_pack_start (GTK_BOX(vbox), ghidgui->layer_selector, 01379 FALSE, FALSE, 0); 01380 01381 /* FIXME: IFDEF HACK */ 01382 #ifdef ENABLE_GL 01383 trackball = ghid_trackball_new (); 01384 g_signal_connect (trackball, "rotation-changed", 01385 G_CALLBACK (ghid_port_rotate), NULL); 01386 g_signal_connect (trackball, "view-2d-changed", 01387 G_CALLBACK (ghid_view_2d), NULL); 01388 gtk_box_pack_start (GTK_BOX(ghidgui->left_toolbar), 01389 trackball, FALSE, FALSE, 0); 01390 #endif 01391 01392 /* ghidgui->mode_buttons_frame was created above in the call to 01393 * make_mode_buttons_and_toolbar (...); 01394 */ 01395 gtk_box_pack_start (GTK_BOX (ghidgui->left_toolbar), 01396 ghidgui->mode_buttons_frame, FALSE, FALSE, 0); 01397 01398 frame = gtk_frame_new(NULL); 01399 gtk_box_pack_end (GTK_BOX (ghidgui->left_toolbar), frame, FALSE, FALSE, 0); 01400 vbox = gtk_vbox_new(FALSE, 0); 01401 gtk_container_add(GTK_CONTAINER(frame), vbox); 01402 hbox = gtk_hbox_new(FALSE, 0); 01403 gtk_box_pack_start(GTK_BOX (vbox), hbox, FALSE, FALSE, 1); 01404 ghidgui->route_style_selector = ghid_route_style_selector_new (); 01405 make_route_style_buttons 01406 (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector)); 01407 gtk_box_pack_start(GTK_BOX(hbox), ghidgui->route_style_selector, 01408 FALSE, FALSE, 0); 01409 01410 ghidgui->vbox_middle = gtk_vbox_new (FALSE, 0); 01411 gtk_box_pack_start (GTK_BOX (hbox_middle), 01412 ghidgui->vbox_middle, TRUE, TRUE, 0); 01413 01414 hbox = gtk_hbox_new (FALSE, 0); 01415 gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle), hbox, TRUE, TRUE, 0); 01416 01417 /* -- The PCB layout output drawing area */ 01418 01419 gport->drawing_area = gtk_drawing_area_new (); 01420 ghid_init_drawing_widget (gport->drawing_area, gport); 01421 01422 gtk_widget_add_events (gport->drawing_area, GDK_EXPOSURE_MASK 01423 | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK 01424 | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK 01425 | GDK_KEY_RELEASE_MASK | GDK_KEY_PRESS_MASK 01426 | GDK_FOCUS_CHANGE_MASK | GDK_POINTER_MOTION_MASK 01427 | GDK_POINTER_MOTION_HINT_MASK); 01428 01429 /* 01430 * This is required to get the drawing_area key-press-event. Also the 01431 * enter and button press callbacks grab focus to be sure we have it 01432 * when in the drawing_area. 01433 */ 01434 gtk_widget_set_can_focus (gport->drawing_area, TRUE); 01435 01436 gtk_box_pack_start (GTK_BOX (hbox), gport->drawing_area, TRUE, TRUE, 0); 01437 01438 ghidgui->v_adjustment = gtk_adjustment_new (0.0, 0.0, 100.0, 01439 10.0, 10.0, 10.0); 01440 ghidgui->v_range = 01441 gtk_vscrollbar_new (GTK_ADJUSTMENT (ghidgui->v_adjustment)); 01442 01443 gtk_box_pack_start (GTK_BOX (hbox), ghidgui->v_range, FALSE, FALSE, 0); 01444 01445 g_signal_connect (G_OBJECT (ghidgui->v_adjustment), "value_changed", 01446 G_CALLBACK (v_adjustment_changed_cb), ghidgui); 01447 01448 ghidgui->h_adjustment = gtk_adjustment_new (0.0, 0.0, 100.0, 01449 10.0, 10.0, 10.0); 01450 ghidgui->h_range = 01451 gtk_hscrollbar_new (GTK_ADJUSTMENT (ghidgui->h_adjustment)); 01452 gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle), 01453 ghidgui->h_range, FALSE, FALSE, 0); 01454 01455 g_signal_connect (G_OBJECT (ghidgui->h_adjustment), "value_changed", 01456 G_CALLBACK (h_adjustment_changed_cb), ghidgui); 01457 01458 /* -- The bottom status line label */ 01459 ghidgui->status_line_hbox = gtk_hbox_new (FALSE, 0); 01460 gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle), 01461 ghidgui->status_line_hbox, FALSE, FALSE, 0); 01462 01463 label = gtk_label_new (""); 01464 gtk_label_set_use_markup (GTK_LABEL (label), TRUE); 01465 gtk_box_pack_start (GTK_BOX (ghidgui->status_line_hbox), label, FALSE, 01466 FALSE, 0); 01467 ghidgui->status_line_label = label; 01468 01469 /* Depending on user setting, the command_combo_box may get packed into 01470 | the status_line_hbox, but it will happen on demand the first time 01471 | the user does a command entry. 01472 */ 01473 01474 g_signal_connect (G_OBJECT (gport->drawing_area), "realize", 01475 G_CALLBACK (ghid_port_drawing_realize_cb), 01476 port); 01477 g_signal_connect (G_OBJECT (gport->drawing_area), "expose_event", 01478 G_CALLBACK (ghid_drawing_area_expose_cb), 01479 port); 01480 g_signal_connect (G_OBJECT (gport->top_window), "configure_event", 01481 G_CALLBACK (top_window_configure_event_cb), port); 01482 g_signal_connect (gport->top_window, "enter-notify-event", 01483 G_CALLBACK (top_window_enter_cb), port); 01484 g_signal_connect (G_OBJECT (gport->drawing_area), "configure_event", 01485 G_CALLBACK (ghid_port_drawing_area_configure_event_cb), 01486 port); 01487 01488 01489 /* Mouse and key events will need to be intercepted when PCB needs a 01490 | location from the user. 01491 */ 01492 01493 ghid_interface_input_signals_connect (); 01494 01495 g_signal_connect (G_OBJECT (gport->drawing_area), "enter_notify_event", 01496 G_CALLBACK (ghid_port_window_enter_cb), port); 01497 g_signal_connect (G_OBJECT (gport->drawing_area), "leave_notify_event", 01498 G_CALLBACK (ghid_port_window_leave_cb), port); 01499 g_signal_connect (G_OBJECT (gport->drawing_area), "motion_notify_event", 01500 G_CALLBACK (ghid_port_window_motion_cb), port); 01501 01502 01503 01504 g_signal_connect (G_OBJECT (window), "delete_event", 01505 G_CALLBACK (delete_chart_cb), port); 01506 g_signal_connect (G_OBJECT (window), "destroy", 01507 G_CALLBACK (destroy_chart_cb), port); 01508 01509 ghidgui->creating = FALSE; 01510 01511 gtk_widget_show_all (gport->top_window); 01512 ghid_pack_mode_buttons (); 01513 gdk_window_set_back_pixmap (gtk_widget_get_window (gport->drawing_area), 01514 NULL, FALSE); 01515 01516 port->tooltip_update_timeout_id = 0; 01517 } 01518 01519 01520 /* Connect and disconnect just the signals a g_main_loop() will need. 01521 | Cursor and motion events still need to be handled by the top level 01522 | loop, so don't connect/reconnect these. 01523 | A g_main_loop will be running when PCB wants the user to select a 01524 | location or if command entry is needed in the status line hbox. 01525 | During these times normal button/key presses are intercepted, either 01526 | by new signal handlers or the command_combo_box entry. 01527 */ 01528 static gulong button_press_handler; 01529 static gulong button_release_handler; 01530 static gulong scroll_event_handler; 01531 static gulong key_press_handler; 01532 static gulong key_release_handler; 01533 01544 void 01545 ghid_interface_input_signals_connect (void) 01546 { 01547 button_press_handler = 01548 g_signal_connect (G_OBJECT (gport->drawing_area), "button_press_event", 01549 G_CALLBACK (ghid_port_button_press_cb), NULL); 01550 01551 button_release_handler = 01552 g_signal_connect (G_OBJECT (gport->drawing_area), "button_release_event", 01553 G_CALLBACK (ghid_port_button_release_cb), NULL); 01554 01555 scroll_event_handler = 01556 g_signal_connect (G_OBJECT (gport->drawing_area), "scroll_event", 01557 G_CALLBACK (ghid_port_window_mouse_scroll_cb), NULL); 01558 01559 key_press_handler = 01560 g_signal_connect (G_OBJECT (gport->drawing_area), "key_press_event", 01561 G_CALLBACK (ghid_port_key_press_cb), NULL); 01562 01563 key_release_handler = 01564 g_signal_connect (G_OBJECT (gport->drawing_area), "key_release_event", 01565 G_CALLBACK (ghid_port_key_release_cb), NULL); 01566 } 01567 01578 void 01579 ghid_interface_input_signals_disconnect (void) 01580 { 01581 if (button_press_handler) 01582 g_signal_handler_disconnect (gport->drawing_area, button_press_handler); 01583 01584 if (button_release_handler) 01585 g_signal_handler_disconnect (gport->drawing_area, button_release_handler); 01586 01587 if (scroll_event_handler) 01588 g_signal_handler_disconnect (gport->drawing_area, scroll_event_handler); 01589 01590 if (key_press_handler) 01591 g_signal_handler_disconnect (gport->drawing_area, key_press_handler); 01592 01593 if (key_release_handler) 01594 g_signal_handler_disconnect (gport->drawing_area, key_release_handler); 01595 01596 button_press_handler = 0; 01597 button_release_handler = 0; 01598 scroll_event_handler = 0; 01599 key_press_handler = 0; 01600 key_release_handler = 0; 01601 } 01602 01603 01609 void 01610 ghid_interface_set_sensitive (gboolean sensitive) 01611 { 01612 gtk_widget_set_sensitive (ghidgui->left_toolbar, sensitive); 01613 gtk_widget_set_sensitive (ghidgui->menu_hbox, sensitive); 01614 } 01615 01616 01620 static void 01621 ghid_init_icons (GHidPort * port) 01622 { 01623 GdkWindow *window = gtk_widget_get_window (gport->top_window); 01624 01625 XC_clock_source = gdk_bitmap_create_from_data (window, 01626 (char *) rotateIcon_bits, 01627 rotateIcon_width, 01628 rotateIcon_height); 01629 XC_clock_mask = 01630 gdk_bitmap_create_from_data (window, (char *) rotateMask_bits, 01631 rotateMask_width, rotateMask_height); 01632 01633 XC_hand_source = gdk_bitmap_create_from_data (window, 01634 (char *) handIcon_bits, 01635 handIcon_width, 01636 handIcon_height); 01637 XC_hand_mask = 01638 gdk_bitmap_create_from_data (window, (char *) handMask_bits, 01639 handMask_width, handMask_height); 01640 01641 XC_lock_source = gdk_bitmap_create_from_data (window, 01642 (char *) lockIcon_bits, 01643 lockIcon_width, 01644 lockIcon_height); 01645 XC_lock_mask = 01646 gdk_bitmap_create_from_data (window, (char *) lockMask_bits, 01647 lockMask_width, lockMask_height); 01648 } 01649 01650 void 01651 ghid_create_pcb_widgets (void) 01652 { 01653 GHidPort *port = &ghid_port; 01654 GError *err = NULL; 01655 01656 if (bg_image_file) 01657 ghidgui->bg_pixbuf = gdk_pixbuf_new_from_file(bg_image_file, &err); 01658 if (err) 01659 { 01660 g_error("%s", err->message); 01661 g_error_free(err); 01662 } 01663 ghid_build_pcb_top_window (); 01664 ghid_install_accel_groups (GTK_WINDOW (port->top_window), ghidgui); 01665 ghid_update_toggle_flags (); 01666 01667 ghid_init_icons (port); 01668 SetMode (ARROW_MODE); 01669 ghid_mode_buttons_update (); 01670 } 01671 01672 static gboolean 01673 ghid_listener_cb (GIOChannel *source, 01674 GIOCondition condition, 01675 gpointer data) 01676 { 01677 GIOStatus status; 01678 gchar *str; 01679 gsize len; 01680 gsize term; 01681 GError *err = NULL; 01682 01683 01684 if (condition & G_IO_HUP) 01685 { 01686 gui->log (_("Read end of pipe died!\n")); 01687 return FALSE; 01688 } 01689 01690 if (condition == G_IO_IN) 01691 { 01692 status = g_io_channel_read_line (source, &str, &len, &term, &err); 01693 switch (status) 01694 { 01695 case G_IO_STATUS_NORMAL: 01696 hid_parse_actions (str); 01697 g_free (str); 01698 break; 01699 01700 case G_IO_STATUS_ERROR: 01701 gui->log (_("ERROR status from g_io_channel_read_line\n")); 01702 return FALSE; 01703 break; 01704 01705 case G_IO_STATUS_EOF: 01706 gui->log (_("Input pipe returned EOF. The --listen option is \n" 01707 "probably not running anymore in this session.\n")); 01708 return FALSE; 01709 break; 01710 01711 case G_IO_STATUS_AGAIN: 01712 gui->log (_("AGAIN status from g_io_channel_read_line\n")); 01713 return FALSE; 01714 break; 01715 01716 default: 01717 fprintf (stderr, _("ERROR: unhandled case in ghid_listener_cb\n")); 01718 return FALSE; 01719 break; 01720 } 01721 01722 } 01723 else 01724 fprintf (stderr, _("Unknown condition in ghid_listener_cb\n")); 01725 01726 return TRUE; 01727 } 01728 01729 static void 01730 ghid_create_listener (void) 01731 { 01732 GIOChannel *channel; 01733 int fd = fileno (stdin); 01734 01735 channel = g_io_channel_unix_new (fd); 01736 g_io_add_watch (channel, G_IO_IN, ghid_listener_cb, NULL); 01737 } 01738 01739 01740 /* ------------------------------------------------------------ */ 01741 01742 static int stdin_listen = 0; 01743 static char *pcbmenu_path = "gpcb-menu.res"; 01744 01745 HID_Attribute ghid_attribute_list[] = { 01746 01747 /* %start-doc options "21 GTK+ GUI Options" 01748 @ftable @code 01749 @item --listen 01750 Listen for actions on stdin. 01751 @end ftable 01752 %end-doc 01753 */ 01754 {"listen", N_("Listen for actions on stdin"), 01755 HID_Boolean, 0, 0, {0, 0, 0}, 0, &stdin_listen}, 01756 #define HA_listen 0 01757 01758 /* %start-doc options "21 GTK+ GUI Options" 01759 @ftable @code 01760 @item --bg-image <string> 01761 File name of an image to put into the background of the GUI canvas. The image must 01762 be a color PPM image, in binary (not ASCII) format. It can be any size, and will be 01763 automatically scaled to fit the canvas. 01764 @end ftable 01765 %end-doc 01766 */ 01767 {"bg-image", N_("Background Image"), 01768 HID_String, 0, 0, {0, 0, 0}, 0, &bg_image_file}, 01769 #define HA_bg_image 1 01770 01771 /* %start-doc options "21 GTK+ GUI Options" 01772 @ftable @code 01773 @item --pcb-menu <string> 01774 Location of the @file{gpcb-menu.res} file which defines the menu for the GTK+ GUI. 01775 @end ftable 01776 %end-doc 01777 */ 01778 {"pcb-menu", N_("Location of gpcb-menu.res file"), 01779 HID_String, 0, 0, {0, PCBLIBDIR "/gpcb-menu.res", 0}, 0, &pcbmenu_path} 01780 #define HA_pcbmenu 2 01781 }; 01782 01783 REGISTER_ATTRIBUTES (ghid_attribute_list) 01784 01785 HID_Attribute * 01786 ghid_get_export_options (int *n_ret) 01787 { 01788 *n_ret = sizeof (ghid_attribute_list) / sizeof (HID_Attribute); 01789 return ghid_attribute_list; 01790 } 01791 01796 void 01797 ghid_parse_arguments (int *argc, char ***argv) 01798 { 01799 GtkWidget *window; 01800 gint i; 01801 GdkPixbuf *icon; 01802 01803 /* on windows we need to figure out the installation directory */ 01804 #ifdef WIN32 01805 char * tmps; 01806 char * libdir; 01807 tmps = g_win32_get_package_installation_directory_of_module (NULL); 01808 #define REST_OF_PATH G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S PACKAGE G_DIR_SEPARATOR_S "newlib" 01809 libdir = (char *) malloc(strlen(tmps) + 01810 strlen(REST_OF_PATH) + 01811 1); 01812 sprintf(libdir, "%s%s", tmps, REST_OF_PATH); 01813 free(tmps); 01814 01815 Settings.LibraryTree = libdir; 01816 01817 #undef REST_OF_PATH 01818 01819 #endif 01820 01821 #if defined (DEBUG) 01822 for (i = 0; i < *argc; i++) 01823 { 01824 printf ("ghid_parse_arguments(): *argv[%d] = \"%s\"\n", i, (*argv)[i]); 01825 } 01826 #endif 01827 01828 /* Threads aren't used in PCB, but this call would go here. 01829 */ 01830 /* g_thread_init (NULL); */ 01831 01832 /* 01833 * Prevent gtk_init() and gtk_init_check() from automatically calling 01834 * setlocale (LC_ALL, "") which would undo LC_NUMERIC handling in main(). 01835 */ 01836 gtk_disable_setlocale (); 01837 01838 gtk_init (argc, argv); 01839 01840 gport = &ghid_port; 01841 gport->view.coord_per_px = 300.0; 01842 pixel_slop = 300; 01843 01844 ghid_init_renderer (argc, argv, gport); 01845 01846 ghid_config_files_read (argc, argv); 01847 01848 Settings.AutoPlace = 0; 01849 for (i = 0; i < *argc; i++) 01850 { 01851 if (strcmp ((*argv)[i], "-auto-place") == 0) 01852 Settings.AutoPlace = 1; 01853 } 01854 01855 bindtextdomain (PACKAGE, LOCALEDIR); 01856 textdomain (PACKAGE); 01857 bind_textdomain_codeset (PACKAGE, "UTF-8"); 01858 01859 icon = gdk_pixbuf_new_from_xpm_data ((const gchar **) icon_bits); 01860 gtk_window_set_default_icon (icon); 01861 01862 window = gport->top_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); 01863 gtk_window_set_title (GTK_WINDOW (window), "PCB"); 01864 gtk_window_resize (GTK_WINDOW(window), 01865 ghidgui->top_window_width, ghidgui->top_window_height); 01866 01867 if (Settings.AutoPlace) 01868 gtk_window_move (GTK_WINDOW (window), 10, 10); 01869 01870 gtk_widget_show_all (gport->top_window); 01871 ghidgui->creating = TRUE; 01872 } 01873 01874 void 01875 ghid_do_export (HID_Attr_Val * options) 01876 { 01877 ghid_create_pcb_widgets (); 01878 01879 /* These are needed to make sure the @layerpick and @layerview menus 01880 * are properly initialized and synchronized with the current PCB. 01881 */ 01882 ghid_layer_buttons_update (); 01883 ghid_main_menu_install_route_style_selector 01884 (GHID_MAIN_MENU (ghidgui->menu_bar), 01885 GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector)); 01886 01887 if (stdin_listen) 01888 ghid_create_listener (); 01889 01890 ghid_notify_gui_is_up (); 01891 01892 gtk_main (); 01893 ghid_config_files_write (); 01894 01895 } 01896 01900 static gboolean 01901 get_layer_visible_cb (int id) 01902 { 01903 int visible; 01904 layer_process (NULL, NULL, &visible, id); 01905 return visible; 01906 } 01907 01908 gint 01909 LayersChanged (int argc, char **argv, Coord x, Coord y) 01910 { 01911 if (!ghidgui || !ghidgui->menu_bar) 01912 return 0; 01913 01914 ghid_config_groups_changed(); 01915 ghid_layer_buttons_update (); 01916 ghid_layer_selector_show_layers 01917 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), get_layer_visible_cb); 01918 01924 pcb_colors_from_settings (PCB); 01925 return 0; 01926 } 01927 01928 static const char toggleview_syntax[] = 01929 N_("ToggleView(1..MAXLAYER)\n" 01930 "ToggleView(layername)\n" 01931 "ToggleView(Silk|Rats|Pins|Vias|Mask|BackSide)"); 01932 01933 static const char toggleview_help[] = 01934 N_("Toggle the visibility of the specified layer or layer group."); 01935 01936 /* %start-doc actions ToggleView 01937 01938 If you pass an integer, that layer is specified by index (the first 01939 layer is @code{1}, etc). If you pass a layer name, that layer is 01940 specified by name. When a layer is specified, the visibility of the 01941 layer group containing that layer is toggled. 01942 01943 If you pass a special layer name, the visibility of those components 01944 (silk, rats, etc) is toggled. Note that if you have a layer named 01945 the same as a special layer, the layer is chosen over the special layer. 01946 01947 %end-doc */ 01948 01949 static int 01950 ToggleView (int argc, char **argv, Coord x, Coord y) 01951 { 01952 int i, l; 01953 01954 #ifdef DEBUG_MENUS 01955 puts ("Starting ToggleView()."); 01956 #endif 01957 01958 if (argc == 0) 01959 { 01960 AFAIL (toggleview); 01961 } 01962 if (isdigit ((int) argv[0][0])) 01963 { 01964 l = atoi (argv[0]) - 1; 01965 } 01966 else if (strcmp (argv[0], "Silk") == 0) 01967 l = LAYER_BUTTON_SILK; 01968 else if (strcmp (argv[0], "Rats") == 0) 01969 l = LAYER_BUTTON_RATS; 01970 else if (strcmp (argv[0], "Pins") == 0) 01971 l = LAYER_BUTTON_PINS; 01972 else if (strcmp (argv[0], "Vias") == 0) 01973 l = LAYER_BUTTON_VIAS; 01974 else if (strcmp (argv[0], "Mask") == 0) 01975 l = LAYER_BUTTON_MASK; 01976 else if (strcmp (argv[0], "BackSide") == 0) 01977 l = LAYER_BUTTON_FARSIDE; 01978 else 01979 { 01980 l = -1; 01981 for (i = 0; i < max_copper_layer + SILK_LAYER; i++) 01982 if (strcmp (argv[0], PCB->Data->Layer[i].Name) == 0) 01983 { 01984 l = i; 01985 break; 01986 } 01987 if (l == -1) 01988 { 01989 AFAIL (toggleview); 01990 } 01991 01992 } 01993 01994 /* Now that we've figured out which toggle button ought to control 01995 * this layer, simply hit the button and let the pre-existing code deal 01996 */ 01997 ghid_layer_selector_toggle_layer 01998 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), l); 01999 return 0; 02000 } 02001 02002 static const char selectlayer_syntax[] = 02003 N_("SelectLayer(1..MAXLAYER|Silk|Rats)"); 02004 02005 static const char selectlayer_help[] = 02006 N_("Select which layer is the current layer."); 02007 02008 /* %start-doc actions SelectLayer 02009 02010 The specified layer becomes the currently active layer. It is made 02011 visible if it is not already visible 02012 02013 %end-doc */ 02014 02015 static int 02016 SelectLayer (int argc, char **argv, Coord x, Coord y) 02017 { 02018 int i; 02019 int newl = -1; 02020 if (argc == 0) 02021 AFAIL (selectlayer); 02022 02023 for (i = 0; i < max_copper_layer; ++i) 02024 if (strcasecmp (argv[0], PCB->Data->Layer[i].Name) == 0) 02025 newl = i; 02026 02027 if (strcasecmp (argv[0], "silk") == 0) 02028 newl = LAYER_BUTTON_SILK; 02029 else if (strcasecmp (argv[0], "rats") == 0) 02030 newl = LAYER_BUTTON_RATS; 02031 else if (newl == -1) 02032 newl = atoi (argv[0]) - 1; 02033 02034 #ifdef DEBUG_MENUS 02035 printf ("SelectLayer(): newl = %d\n", newl); 02036 #endif 02037 02038 /* Now that we've figured out which radio button ought to select 02039 * this layer, simply hit the button and let the pre-existing code deal 02040 */ 02041 ghid_layer_selector_select_layer 02042 (GHID_LAYER_SELECTOR (ghidgui->layer_selector), newl); 02043 02044 return 0; 02045 } 02046 02047 02048 HID_Action gtk_topwindow_action_list[] = { 02049 {"LayersChanged", 0, LayersChanged, 02050 layerschanged_help, layerschanged_syntax}, 02051 {"SelectLayer", 0, SelectLayer, 02052 selectlayer_help, selectlayer_syntax}, 02053 {"ToggleView", 0, ToggleView, 02054 toggleview_help, toggleview_syntax} 02055 }; 02056 02057 REGISTER_ACTIONS (gtk_topwindow_action_list) 02058 02059 02069 static void 02070 ghid_check_special_key (const char *accel, GtkAction *action, 02071 const Resource *node) 02072 { 02073 size_t len; 02074 unsigned int mods; 02075 unsigned int ind; 02076 02077 if (action == NULL || accel == NULL || *accel == '\0') 02078 return ; 02079 02080 #ifdef DEBUG_MENUS 02081 printf ("%s(\"%s\", \"%s\")\n", __FUNCTION__, accel, name); 02082 #endif 02083 02084 mods = 0; 02085 if (strstr (accel, "<alt>") ) 02086 { 02087 mods |= GHID_KEY_ALT; 02088 } 02089 if (strstr (accel, "<ctrl>") ) 02090 { 02091 mods |= GHID_KEY_CONTROL; 02092 } 02093 if (strstr (accel, "<shift>") ) 02094 { 02095 mods |= GHID_KEY_SHIFT; 02096 } 02097 02098 02099 len = strlen (accel); 02100 02101 #define CHECK_KEY(a) ((len >= strlen (a)) && (strcmp (accel + len - strlen (a), (a)) == 0)) 02102 02103 ind = 0; 02104 if ( CHECK_KEY ("Tab") ) 02105 { 02106 ind = mods | GHID_KEY_TAB; 02107 } 02108 else if ( CHECK_KEY ("Up") ) 02109 { 02110 ind = mods | GHID_KEY_UP; 02111 } 02112 else if ( CHECK_KEY ("Down") ) 02113 { 02114 ind = mods | GHID_KEY_DOWN; 02115 } 02116 else if ( CHECK_KEY ("Left") ) 02117 { 02118 ind = mods | GHID_KEY_LEFT; 02119 } 02120 else if ( CHECK_KEY ("Right") ) 02121 { 02122 ind = mods | GHID_KEY_RIGHT; 02123 } 02124 02125 if (ind > 0) 02126 { 02127 if (ind >= N_HOTKEY_ACTIONS) 02128 { 02129 fprintf (stderr, _("ERROR: overflow of the ghid_hotkey_actions array. Index = %d\n" 02130 "Please report this.\n"), ind); 02131 exit (1); 02132 } 02133 02134 ghid_hotkey_actions[ind].action = action; 02135 ghid_hotkey_actions[ind].node = node; 02136 #ifdef DEBUG_MENUS 02137 printf ("Adding \"special\" hotkey to ghid_hotkey_actions[%u] :" 02138 " %s (%s)\n", ind, accel, name); 02139 #endif 02140 } 02141 } 02142 02146 char * 02147 get_menu_filename (void) 02148 { 02149 char *rv = NULL; 02150 char *home_pcbmenu = NULL; 02151 02152 /* homedir is set by the core */ 02153 if (homedir) 02154 { 02155 Message (_("Note: home directory is \"%s\"\n"), homedir); 02156 home_pcbmenu = Concat (homedir, PCB_DIR_SEPARATOR_S, ".pcb", 02157 PCB_DIR_SEPARATOR_S, "gpcb-menu.res", NULL); 02158 } 02159 else 02160 Message (_("Warning: could not determine home directory\n")); 02161 02162 if (access ("gpcb-menu.res", R_OK) == 0) 02163 rv = strdup ("gpcb-menu.res"); 02164 else if (home_pcbmenu != NULL && (access (home_pcbmenu, R_OK) == 0) ) 02165 rv = home_pcbmenu; 02166 else if (access (pcbmenu_path, R_OK) == 0) 02167 rv = strdup (pcbmenu_path); 02168 02169 return rv; 02170 } 02171 02172 static GtkWidget * 02173 ghid_load_menus (void) 02174 { 02175 char *filename; 02176 const Resource *r = 0, *bir; 02177 const Resource *mr; 02178 GtkWidget *menu_bar = NULL; 02179 int i; 02180 02181 for (i = 0; i < N_HOTKEY_ACTIONS; i++) 02182 { 02183 ghid_hotkey_actions[i].action = NULL; 02184 ghid_hotkey_actions[i].node = NULL; 02185 } 02186 02187 bir = resource_parse (0, gpcb_menu_default); 02188 if (!bir) 02189 { 02190 fprintf (stderr, _("Error: internal menu resource didn't parse\n")); 02191 exit(1); 02192 } 02193 02194 filename = get_menu_filename (); 02195 if (filename) 02196 { 02197 Message (_("Loading menus from %s\n"), filename); 02198 r = resource_parse (filename, 0); 02199 } 02200 02201 if (!r) 02202 { 02203 Message (_("Using default menus\n")); 02204 r = bir; 02205 } 02206 free (filename); 02207 02208 mr = resource_subres (r, "MainMenu"); 02209 if (!mr) 02210 mr = resource_subres (bir, "MainMenu"); 02211 02212 if (mr) 02213 { 02214 menu_bar = ghid_main_menu_new (G_CALLBACK (ghid_menu_cb), 02215 ghid_check_special_key); 02216 ghid_main_menu_add_resource (GHID_MAIN_MENU (menu_bar), mr); 02217 } 02218 02219 mr = resource_subres (r, "PopupMenus"); 02220 if (!mr) 02221 mr = resource_subres (bir, "PopupMenus"); 02222 02223 if (mr) 02224 { 02225 int i; 02226 for (i = 0; i < mr->c; i++) 02227 if (resource_type (mr->v[i]) == 101) 02228 /* This is a named resource which defines a popup menu */ 02229 ghid_main_menu_add_popup_resource (GHID_MAIN_MENU (menu_bar), 02230 mr->v[i].name, mr->v[i].subres); 02231 } 02232 02233 #ifdef DEBUG_MENUS 02234 puts ("Finished loading menus."); 02235 #endif 02236 02237 mr = resource_subres (r, "Mouse"); 02238 if (!mr) 02239 mr = resource_subres (bir, "Mouse"); 02240 if (mr) 02241 load_mouse_resource (mr); 02242 02243 return menu_bar; 02244 } 02245 02246 /* ------------------------------------------------------------ */ 02247 02248 static const char adjuststyle_syntax[] = 02249 N_("AdjustStyle()\n"); 02250 02251 static const char adjuststyle_help[] = 02252 N_("Open the window which allows editing of the route styles."); 02253 02254 /* %start-doc actions AdjustStyle 02255 02256 Opens the window which allows editing of the route styles. 02257 02258 %end-doc */ 02259 02260 static int 02261 AdjustStyle(int argc, char **argv, Coord x, Coord y) 02262 { 02263 ghid_route_style_selector_edit_dialog 02264 (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector)); 02265 02266 return 0; 02267 } 02268 02269 /* ------------------------------------------------------------ */ 02270 02271 static const char editlayergroups_syntax[] = 02272 N_("EditLayerGroups()\n"); 02273 02274 static const char editlayergroups_help[] = 02275 N_("Open the preferences window which allows editing of the layer groups."); 02276 02277 /* %start-doc actions EditLayerGroups 02278 02279 Opens the preferences window which is where the layer groups 02280 are edited. This action is primarily provides to provide menu 02281 resource compatibility with the lesstif HID. 02282 02283 %end-doc */ 02284 02285 static int 02286 EditLayerGroups(int argc, char **argv, Coord x, Coord y) 02287 { 02288 02289 if (argc != 0) 02290 AFAIL (editlayergroups); 02291 02292 hid_actionl ("DoWindows", "Preferences", NULL); 02293 02294 return 0; 02295 } 02296 02297 /* ------------------------------------------------------------ */ 02298 02299 HID_Action ghid_menu_action_list[] = { 02300 {"AdjustStyle", 0, AdjustStyle, adjuststyle_help, adjuststyle_syntax}, 02301 {"EditLayerGroups", 0, EditLayerGroups, editlayergroups_help, editlayergroups_syntax} 02302 }; 02303 02304 REGISTER_ACTIONS (ghid_menu_action_list) 02305