4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 /* #define DEBUG_MENUS */
28 - figure out when we need to call
this:
29 ghid_set_status_line_label ();
32 - the old quit callback had
:
34 ghid_config_files_write ();
37 - what about stuff like
this:
39 /* Set to ! because ActionDisplay toggles it */
40 Settings
.DrawGrid
= !gtk_toggle_action_get_active (action
);
41 ghidgui
->config_modified
= TRUE
;
42 hid_actionl ("Display", "Grid", "", NULL
);
43 ghid_set_status_line_label ();
46 I NEED TO DO THE STATUS LINE THING
. for example shift
-alt
-v to change the
47 via size
. NOte the status line label does
not get updated properly until
52 /* This file was originally written by Bill Wilson for the PCB Gtk
53 * port. It was later heavily modified by Dan McMahill to provide
54 * user customized menus.
59 | This handles creation of the top level window and all its widgets.
60 | events for the Output.drawing_area widget are handled in a separate
61 | file gui-output-events.c
63 | Some caveats with menu shorcut keys: Some keys are trapped out by Gtk
64 | and can't be used as shortcuts (eg. '|', TAB, etc). For these cases
65 | we have our own shortcut table and capture the keys and send the events
66 | there in ghid_port_key_press_cb().
80 #include "ghid-layer-selector.h"
81 #include "ghid-route-style-selector.h"
85 #include "../hidint.h"
86 #include "hid/common/hid_resource.h"
89 #include "autoplace.h"
90 #include "autoroute.h"
96 #include "crosshair.h"
101 #include "gpcb-menu.h"
107 #include "pcb-printf.h"
112 #include "resource.h"
114 #include "rubberband.h"
120 #include "free_atexit.h"
122 #include "gui-icons-mode-buttons.data"
123 #include "gui-icons-misc.data"
125 #ifdef HAVE_LIBDMALLOC
129 static bool ignore_layer_update
;
131 static GtkWidget
*ghid_load_menus (void);
133 GhidGui _ghidgui
, *ghidgui
= NULL
;
135 GHidPort ghid_port
, *gport
;
137 static gchar
*bg_image_file
;
139 static struct { GtkAction
*action
; const Resource
*node
; }
140 ghid_hotkey_actions
[256];
141 #define N_HOTKEY_ACTIONS \
142 (sizeof (ghid_hotkey_actions) / sizeof (ghid_hotkey_actions[0]))
145 /*! \brief callback for ghid_main_menu_update_toggle_state () */
147 menu_toggle_update_cb (GtkAction
*act
, const char *tflag
, const char *aflag
)
151 int v
= hid_get_flag (tflag
);
152 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (act
), !!v
);
156 int v
= hid_get_flag (aflag
);
157 gtk_action_set_sensitive (act
, !!v
);
161 /*! \brief sync the menu checkboxes with actual pcb state */
163 ghid_update_toggle_flags ()
165 ghid_main_menu_update_toggle_state (GHID_MAIN_MENU (ghidgui
->menu_bar
),
166 menu_toggle_update_cb
);
170 h_adjustment_changed_cb (GtkAdjustment
* adj
, GhidGui
* g
)
172 if (g
->adjustment_changed_holdoff
)
175 ghid_port_ranges_changed ();
179 v_adjustment_changed_cb (GtkAdjustment
* adj
, GhidGui
* g
)
181 if (g
->adjustment_changed_holdoff
)
184 ghid_port_ranges_changed ();
187 /* Save size of top window changes so PCB can restart at its size at exit.
190 top_window_configure_event_cb (GtkWidget
* widget
, GdkEventConfigure
* ev
,
193 GtkAllocation allocation
;
194 gboolean new_w
, new_h
;
196 gtk_widget_get_allocation (widget
, &allocation
);
198 new_w
= (ghidgui
->top_window_width
!= allocation
.width
);
199 new_h
= (ghidgui
->top_window_height
!= allocation
.height
);
201 ghidgui
->top_window_width
= allocation
.width
;
202 ghidgui
->top_window_height
= allocation
.height
;
205 ghidgui
->config_modified
= TRUE
;
211 info_bar_response_cb (GtkInfoBar
*info_bar
,
215 gtk_widget_destroy (_gui
->info_bar
);
216 _gui
->info_bar
= NULL
;
218 if (response_id
== GTK_RESPONSE_ACCEPT
)
223 close_file_modified_externally_prompt (void)
225 if (ghidgui
->info_bar
!= NULL
)
226 gtk_widget_destroy (ghidgui
->info_bar
);
227 ghidgui
->info_bar
= NULL
;
231 show_file_modified_externally_prompt (void)
234 GtkWidget
*button_image
;
237 GtkWidget
*content_area
;
238 char *file_path_utf8
;
239 char *secondary_text
;
242 close_file_modified_externally_prompt ();
244 ghidgui
->info_bar
= gtk_info_bar_new ();
246 button
= gtk_info_bar_add_button (GTK_INFO_BAR (ghidgui
->info_bar
),
248 GTK_RESPONSE_ACCEPT
);
249 button_image
= gtk_image_new_from_stock (GTK_STOCK_REFRESH
,
250 GTK_ICON_SIZE_BUTTON
);
251 gtk_button_set_image (GTK_BUTTON (button
), button_image
);
253 gtk_info_bar_add_button (GTK_INFO_BAR (ghidgui
->info_bar
),
255 GTK_RESPONSE_CANCEL
);
256 gtk_info_bar_set_message_type (GTK_INFO_BAR (ghidgui
->info_bar
),
257 GTK_MESSAGE_WARNING
);
258 gtk_box_pack_start (GTK_BOX (ghidgui
->vbox_middle
),
259 ghidgui
->info_bar
, FALSE
, FALSE
, 0);
260 gtk_box_reorder_child (GTK_BOX (ghidgui
->vbox_middle
), ghidgui
->info_bar
, 0);
263 g_signal_connect (ghidgui
->info_bar
, "response",
264 G_CALLBACK (info_bar_response_cb
), ghidgui
);
266 file_path_utf8
= g_filename_to_utf8 (PCB
->Filename
, -1, NULL
, NULL
, NULL
);
268 secondary_text
= PCB
->Changed
? "Do you want to drop your changes and reload the file?" :
269 "Do you want to reload the file?";
271 markup
= g_markup_printf_escaped (_("<b>The file %s has changed on disk</b>\n\n%s"),
272 file_path_utf8
, secondary_text
);
273 g_free (file_path_utf8
);
275 content_area
= gtk_info_bar_get_content_area (GTK_INFO_BAR (ghidgui
->info_bar
));
277 icon
= gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING
,
278 GTK_ICON_SIZE_DIALOG
);
279 gtk_box_pack_start (GTK_BOX (content_area
),
280 icon
, FALSE
, FALSE
, 0);
282 label
= gtk_label_new ("");
283 gtk_box_pack_start (GTK_BOX (content_area
),
284 label
, TRUE
, TRUE
, 6);
286 gtk_label_set_use_markup (GTK_LABEL (label
), TRUE
);
287 gtk_label_set_markup (GTK_LABEL (label
), markup
);
290 gtk_misc_set_alignment (GTK_MISC (label
), 0., 0.5);
292 gtk_widget_show_all (ghidgui
->info_bar
);
296 check_externally_modified (void)
302 /* Treat zero time as a flag to indicate we've not got an mtime yet */
303 if (PCB
->Filename
== NULL
||
304 (ghidgui
->our_mtime
.tv_sec
== 0 &&
305 ghidgui
->our_mtime
.tv_usec
== 0))
308 file
= g_file_new_for_path (PCB
->Filename
);
309 info
= g_file_query_info (file
, G_FILE_ATTRIBUTE_TIME_MODIFIED
,
310 G_FILE_QUERY_INFO_NONE
, NULL
, NULL
);
311 g_object_unref (file
);
314 !g_file_info_has_attribute (info
, G_FILE_ATTRIBUTE_TIME_MODIFIED
))
317 g_file_info_get_modification_time (info
, &timeval
); //&ghidgui->last_seen_mtime);
318 g_object_unref (info
);
320 /* Ignore when the file on disk is the same age as when we last looked */
321 if (timeval
.tv_sec
== ghidgui
->last_seen_mtime
.tv_sec
&&
322 timeval
.tv_usec
== ghidgui
->last_seen_mtime
.tv_usec
)
325 ghidgui
->last_seen_mtime
= timeval
;
327 return (ghidgui
->last_seen_mtime
.tv_sec
> ghidgui
->our_mtime
.tv_sec
) ||
328 (ghidgui
->last_seen_mtime
.tv_sec
== ghidgui
->our_mtime
.tv_sec
&&
329 ghidgui
->last_seen_mtime
.tv_usec
> ghidgui
->our_mtime
.tv_usec
);
333 top_window_enter_cb (GtkWidget
*widget
, GdkEvent
*event
, GHidPort
*port
)
335 if (check_externally_modified ())
336 show_file_modified_externally_prompt ();
341 /*! \brief Menu action callback function
342 * \par Function Description
343 * This is the main menu callback function. The callback receives
344 * the original Resource pointer containing the HID actions to be
347 * All hotkeys go through the menus which means they go through here.
348 * Some, such as tab, are caught by Gtk instead of passed here, so
349 * pcb calls this function directly through ghid_hotkey_cb() for them.
351 * \param [in] The action that was activated
352 * \param [in] The menu resource associated with the action
356 ghid_menu_cb (GtkAction
*action
, const Resource
*node
)
360 if (action
== NULL
|| node
== NULL
)
363 for (i
= 1; i
< node
->c
; i
++)
364 if (resource_type (node
->v
[i
]) == 10)
367 printf (" %s\n", node
->v
[i
].value
);
369 hid_parse_actions (node
->v
[i
].value
);
372 /* Sync gui widgets with pcb state */
373 ghid_update_toggle_flags ();
374 ghid_mode_buttons_update ();
376 /* Sync gui status display with pcb state */
377 AdjustAttachedObjects ();
378 ghid_invalidate_all ();
379 ghid_window_set_name_label (PCB
->Name
);
380 ghid_set_status_line_label ();
383 /* \brief Accelerator callback for accelerators gtk tries to hide from us */
384 void ghid_hotkey_cb (int which
)
386 if (ghid_hotkey_actions
[which
].action
!= NULL
)
387 ghid_menu_cb (ghid_hotkey_actions
[which
].action
,
388 (gpointer
) ghid_hotkey_actions
[which
].node
);
392 update_board_mtime_from_disk (void)
397 ghidgui
->our_mtime
.tv_sec
= 0;
398 ghidgui
->our_mtime
.tv_usec
= 0;
399 ghidgui
->last_seen_mtime
= ghidgui
->our_mtime
;
401 if (PCB
->Filename
== NULL
)
404 file
= g_file_new_for_path (PCB
->Filename
);
405 info
= g_file_query_info (file
, G_FILE_ATTRIBUTE_TIME_MODIFIED
,
406 G_FILE_QUERY_INFO_NONE
, NULL
, NULL
);
407 g_object_unref (file
);
410 !g_file_info_has_attribute (info
, G_FILE_ATTRIBUTE_TIME_MODIFIED
))
413 g_file_info_get_modification_time (info
, &ghidgui
->our_mtime
);
414 g_object_unref (info
);
416 ghidgui
->last_seen_mtime
= ghidgui
->our_mtime
;
419 /* Sync toggle states that were saved with the layout and notify the
420 | config code to update Settings values it manages.
423 ghid_sync_with_new_layout (void)
425 pcb_use_route_style (&PCB
->RouteStyle
[0]);
426 ghid_route_style_selector_select_style
427 (GHID_ROUTE_STYLE_SELECTOR (ghidgui
->route_style_selector
),
428 &PCB
->RouteStyle
[0]);
430 ghid_config_handle_units_changed ();
432 ghid_window_set_name_label (PCB
->Name
);
433 ghid_set_status_line_label ();
434 close_file_modified_externally_prompt ();
435 update_board_mtime_from_disk ();
439 ghid_notify_save_pcb (const char *filename
, bool done
)
441 /* Do nothing if it is not the active PCB file that is being saved.
443 if (PCB
->Filename
== NULL
|| strcmp (filename
, PCB
->Filename
) != 0)
447 update_board_mtime_from_disk ();
451 ghid_notify_filename_changed (void)
453 /* Pick up the mtime of the new PCB file */
454 update_board_mtime_from_disk ();
457 /* ---------------------------------------------------------------------------
461 * Takes the index into the layers and produces the text string for
462 * the layer and if the layer is currently visible or not. This is
463 * used by a couple of functions.
467 layer_process (gchar
**color_string
, char **text
, int *set
, int i
)
473 /* cheap hack to let users pass in NULL for either text or set if
474 * they don't care about the result
477 if (color_string
== NULL
)
478 color_string
= &tmpc
;
488 case LAYER_BUTTON_SILK
:
489 *color_string
= Settings
.ElementColor
;
491 *set
= PCB
->ElementOn
;
493 case LAYER_BUTTON_RATS
:
494 *color_string
= Settings
.RatColor
;
495 *text
= _( "rat lines");
498 case LAYER_BUTTON_PINS
:
499 *color_string
= Settings
.PinColor
;
500 *text
= _( "pins/pads");
503 case LAYER_BUTTON_VIAS
:
504 *color_string
= Settings
.ViaColor
;
508 case LAYER_BUTTON_FARSIDE
:
509 *color_string
= Settings
.InvisibleObjectsColor
;
510 *text
= _( "far side");
511 *set
= PCB
->InvisibleObjectsOn
;
513 case LAYER_BUTTON_MASK
:
514 *color_string
= Settings
.MaskColor
;
515 *text
= _( "solder mask");
516 *set
= TEST_FLAG (SHOWMASKFLAG
, PCB
);
518 default: /* layers */
519 *color_string
= Settings
.LayerColor
[i
];
520 *text
= (char *)UNKNOWN (PCB
->Data
->Layer
[i
].Name
);
521 *set
= PCB
->Data
->Layer
[i
].On
;
526 /*! \brief Callback for GHidLayerSelector layer selection */
528 layer_selector_select_callback (GHidLayerSelector
*ls
, int layer
, gpointer d
)
530 ignore_layer_update
= true;
532 PCB
->SilkActive
= (layer
== LAYER_BUTTON_SILK
);
533 PCB
->RatDraw
= (layer
== LAYER_BUTTON_RATS
);
534 if (layer
== LAYER_BUTTON_SILK
)
536 PCB
->ElementOn
= true;
537 hid_action ("LayersChanged");
539 else if (layer
== LAYER_BUTTON_RATS
)
542 hid_action ("LayersChanged");
544 else if (layer
< max_copper_layer
)
545 ChangeGroupVisibility (layer
, TRUE
, true);
547 ignore_layer_update
= false;
549 ghid_invalidate_all ();
552 /*! \brief Callback for GHidLayerSelector layer renaming */
554 layer_selector_rename_callback (GHidLayerSelector
*ls
,
559 LayerType
*layer
= LAYER_PTR (layer_id
);
561 /* Check for a legal layer name - for now, allow anything non-empty */
562 if (new_name
[0] == '\0')
565 /* Don't bother if the name is identical to the current one */
566 if (strcmp (layer
->Name
, new_name
) == 0)
570 layer
->Name
= strdup (new_name
);
571 ghid_layer_buttons_update ();
574 SetChangedFlag (true);
575 ghid_window_set_name_label (PCB
->Name
);
579 /*! \brief Callback for GHidLayerSelector layer toggling */
581 layer_selector_toggle_callback (GHidLayerSelector
*ls
, int layer
, gpointer d
)
583 gboolean redraw
= FALSE
;
585 layer_process (NULL
, NULL
, &active
, layer
);
588 ignore_layer_update
= true;
591 case LAYER_BUTTON_SILK
:
592 PCB
->ElementOn
= active
;
593 PCB
->Data
->SILKLAYER
.On
= PCB
->ElementOn
;
594 PCB
->Data
->BACKSILKLAYER
.On
= PCB
->ElementOn
;
597 case LAYER_BUTTON_RATS
:
601 case LAYER_BUTTON_PINS
:
603 redraw
|= (PCB
->Data
->ElementN
!= 0);
605 case LAYER_BUTTON_VIAS
:
607 redraw
|= (PCB
->Data
->ViaN
!= 0);
609 case LAYER_BUTTON_FARSIDE
:
610 PCB
->InvisibleObjectsOn
= active
;
611 PCB
->Data
->BACKSILKLAYER
.On
= (active
&& PCB
->ElementOn
);
614 case LAYER_BUTTON_MASK
:
616 SET_FLAG (SHOWMASKFLAG
, PCB
);
618 CLEAR_FLAG (SHOWMASKFLAG
, PCB
);
622 /* Flip the visibility */
623 ChangeGroupVisibility (layer
, active
, false);
628 /* Select the next visible layer. (If there is none, this will
629 * select the currently-selected layer, triggering the selection
630 * callback, which will turn the visibility on.) This way we
631 * will never have an invisible layer selected.
634 ghid_layer_selector_select_next_visible (ls
);
636 ignore_layer_update
= false;
639 ghid_invalidate_all();
642 /*! \brief Install menu bar and accelerator groups */
644 ghid_install_accel_groups (GtkWindow
*window
, GhidGui
*gui
)
646 gtk_window_add_accel_group
647 (window
, ghid_main_menu_get_accel_group
648 (GHID_MAIN_MENU (gui
->menu_bar
)));
649 gtk_window_add_accel_group
650 (window
, ghid_layer_selector_get_accel_group
651 (GHID_LAYER_SELECTOR (gui
->layer_selector
)));
652 gtk_window_add_accel_group
653 (window
, ghid_route_style_selector_get_accel_group
654 (GHID_ROUTE_STYLE_SELECTOR (gui
->route_style_selector
)));
657 /*! \brief Remove menu bar and accelerator groups */
659 ghid_remove_accel_groups (GtkWindow
*window
, GhidGui
*gui
)
661 gtk_window_remove_accel_group
662 (window
, ghid_main_menu_get_accel_group
663 (GHID_MAIN_MENU (gui
->menu_bar
)));
664 gtk_window_remove_accel_group
665 (window
, ghid_layer_selector_get_accel_group
666 (GHID_LAYER_SELECTOR (gui
->layer_selector
)));
667 gtk_window_remove_accel_group
668 (window
, ghid_route_style_selector_get_accel_group
669 (GHID_ROUTE_STYLE_SELECTOR (gui
->route_style_selector
)));
672 /* Refreshes the window title bar and sets the PCB name to the
673 * window title bar or to a seperate label
676 ghid_window_set_name_label (gchar
* name
)
681 /* FIXME -- should this happen? It does... */
682 /* This happens if we're calling an exporter from the command line */
686 dup_string (&(ghidgui
->name_label_string
), name
);
687 if (!ghidgui
->name_label_string
|| !*ghidgui
->name_label_string
)
688 ghidgui
->name_label_string
= g_strdup (_("Unnamed"));
690 if (!PCB
->Filename
|| !*PCB
->Filename
)
691 filename
= g_strdup(_("Unsaved.pcb"));
693 filename
= g_strdup(PCB
->Filename
);
695 str
= g_strdup_printf ("%s%s (%s) - PCB", PCB
->Changed
? "*": "",
696 ghidgui
->name_label_string
, filename
);
697 gtk_window_set_title (GTK_WINDOW (gport
->top_window
), str
);
703 grid_units_button_cb (GtkWidget
* widget
, gpointer data
)
705 /* Button only toggles between mm and mil */
706 if (Settings
.grid_unit
== get_unit_struct ("mm"))
707 hid_actionl ("SetUnits", "mil", NULL
);
709 hid_actionl ("SetUnits", "mm", NULL
);
713 * The two following callbacks are used to keep the absolute
714 * and relative cursor labels from growing and shrinking as you
715 * move the cursor around.
718 absolute_label_size_req_cb (GtkWidget
* widget
,
719 GtkRequisition
*req
, gpointer data
)
730 relative_label_size_req_cb (GtkWidget
* widget
,
731 GtkRequisition
*req
, gpointer data
)
742 make_cursor_position_labels (GtkWidget
* hbox
, GHidPort
* port
)
744 GtkWidget
*frame
, *label
;
746 /* The grid units button next to the cursor position labels.
748 ghidgui
->grid_units_button
= gtk_button_new ();
749 label
= gtk_label_new ("");
750 gtk_label_set_markup (GTK_LABEL (label
),
751 Settings
.grid_unit
->in_suffix
);
752 ghidgui
->grid_units_label
= label
;
753 gtk_label_set_use_markup (GTK_LABEL (label
), TRUE
);
754 gtk_container_add (GTK_CONTAINER (ghidgui
->grid_units_button
), label
);
755 gtk_box_pack_end (GTK_BOX (hbox
), ghidgui
->grid_units_button
, FALSE
, TRUE
, 0);
756 g_signal_connect (ghidgui
->grid_units_button
, "clicked",
757 G_CALLBACK (grid_units_button_cb
), NULL
);
759 /* The absolute cursor position label
761 frame
= gtk_frame_new (NULL
);
762 gtk_box_pack_end (GTK_BOX (hbox
), frame
, FALSE
, TRUE
, 0);
763 gtk_container_set_border_width (GTK_CONTAINER (frame
), 2);
764 gtk_frame_set_shadow_type (GTK_FRAME (frame
), GTK_SHADOW_ETCHED_OUT
);
766 label
= gtk_label_new ("");
767 gtk_container_add (GTK_CONTAINER (frame
), label
);
768 ghidgui
->cursor_position_absolute_label
= label
;
769 g_signal_connect (G_OBJECT (label
), "size-request",
770 G_CALLBACK (absolute_label_size_req_cb
), NULL
);
773 /* The relative cursor position label
775 frame
= gtk_frame_new (NULL
);
776 gtk_box_pack_end (GTK_BOX (hbox
), frame
, FALSE
, TRUE
, 0);
777 gtk_container_set_border_width (GTK_CONTAINER (frame
), 2);
778 gtk_frame_set_shadow_type (GTK_FRAME (frame
), GTK_SHADOW_ETCHED_OUT
);
779 label
= gtk_label_new (" __.__ __.__ ");
780 gtk_container_add (GTK_CONTAINER (frame
), label
);
781 ghidgui
->cursor_position_relative_label
= label
;
782 g_signal_connect (G_OBJECT (label
), "size-request",
783 G_CALLBACK (relative_label_size_req_cb
), NULL
);
787 /* \brief Add "virtual layers" to a layer selector */
789 make_virtual_layer_buttons (GtkWidget
*layer_selector
)
791 GHidLayerSelector
*layersel
= GHID_LAYER_SELECTOR (layer_selector
);
796 layer_process (&color_string
, &text
, &active
, LAYER_BUTTON_SILK
);
797 ghid_layer_selector_add_layer (layersel
, LAYER_BUTTON_SILK
,
798 text
, color_string
, active
, TRUE
, FALSE
);
799 layer_process (&color_string
, &text
, &active
, LAYER_BUTTON_RATS
);
800 ghid_layer_selector_add_layer (layersel
, LAYER_BUTTON_RATS
,
801 text
, color_string
, active
, TRUE
, FALSE
);
802 layer_process (&color_string
, &text
, &active
, LAYER_BUTTON_PINS
);
803 ghid_layer_selector_add_layer (layersel
, LAYER_BUTTON_PINS
,
804 text
, color_string
, active
, FALSE
, FALSE
);
805 layer_process (&color_string
, &text
, &active
, LAYER_BUTTON_VIAS
);
806 ghid_layer_selector_add_layer (layersel
, LAYER_BUTTON_VIAS
,
807 text
, color_string
, active
, FALSE
, FALSE
);
808 layer_process (&color_string
, &text
, &active
, LAYER_BUTTON_FARSIDE
);
809 ghid_layer_selector_add_layer (layersel
, LAYER_BUTTON_FARSIDE
,
810 text
, color_string
, active
, FALSE
, FALSE
);
811 layer_process (&color_string
, &text
, &active
, LAYER_BUTTON_MASK
);
812 ghid_layer_selector_add_layer (layersel
, LAYER_BUTTON_MASK
,
813 text
, color_string
, active
, FALSE
, FALSE
);
816 /*! \brief callback for ghid_layer_selector_update_colors */
818 get_layer_color (gint layer
)
821 layer_process (&rv
, NULL
, NULL
, layer
);
825 /*! \brief Update a layer selector's color scheme */
827 ghid_layer_buttons_color_update (void)
829 ghid_layer_selector_update_colors
830 (GHID_LAYER_SELECTOR (ghidgui
->layer_selector
), get_layer_color
);
831 pcb_colors_from_settings (PCB
);
834 /*! \brief Populate a layer selector with all layers Gtk is aware of */
836 make_layer_buttons (GtkWidget
*layersel
)
841 gboolean active
= TRUE
;
843 for (i
= 0; i
< max_copper_layer
; ++i
)
845 layer_process (&color_string
, &text
, &active
, i
);
846 ghid_layer_selector_add_layer (GHID_LAYER_SELECTOR (layersel
), i
,
847 text
, color_string
, active
, TRUE
, TRUE
);
852 /*! \brief callback for ghid_layer_selector_delete_layers */
854 get_layer_delete (gint layer
)
856 return layer
>= max_copper_layer
;
859 /*! \brief Synchronize layer selector widget with current PCB state
860 * \par Function Description
861 * Called when user toggles layer visibility or changes drawing layer,
862 * or when layer visibility is changed programatically.
865 ghid_layer_buttons_update (void)
869 if (ignore_layer_update
)
872 ghid_layer_selector_delete_layers
873 (GHID_LAYER_SELECTOR (ghidgui
->layer_selector
),
875 make_layer_buttons (ghidgui
->layer_selector
);
876 make_virtual_layer_buttons (ghidgui
->layer_selector
);
877 ghid_main_menu_install_layer_selector
878 (GHID_MAIN_MENU (ghidgui
->menu_bar
),
879 GHID_LAYER_SELECTOR (ghidgui
->layer_selector
));
881 /* Sync selected layer with PCB's state */
883 layer
= LAYER_BUTTON_RATS
;
884 else if (PCB
->SilkActive
)
885 layer
= LAYER_BUTTON_SILK
;
887 layer
= LayerStack
[0];
889 ghid_layer_selector_select_layer
890 (GHID_LAYER_SELECTOR (ghidgui
->layer_selector
), layer
);
893 /*! \brief Called when user clicks OK on route style dialog */
895 route_styles_edited_cb (GHidRouteStyleSelector
*rss
, gboolean save
,
900 g_free (Settings
.Routes
);
901 Settings
.Routes
= make_route_string (PCB
->RouteStyle
, NUM_STYLES
);
902 ghidgui
->config_modified
= TRUE
;
903 ghid_config_files_write ();
905 ghid_main_menu_install_route_style_selector
906 (GHID_MAIN_MENU (ghidgui
->menu_bar
),
907 GHID_ROUTE_STYLE_SELECTOR (ghidgui
->route_style_selector
));
910 /*! \brief Called when a route style is selected */
912 route_style_changed_cb (GHidRouteStyleSelector
*rss
, RouteStyleType
*rst
,
915 pcb_use_route_style (rst
);
916 ghid_set_status_line_label();
919 /*! \brief Configure the route style selector */
921 make_route_style_buttons (GHidRouteStyleSelector
*rss
)
924 for (i
= 0; i
< NUM_STYLES
; ++i
)
925 ghid_route_style_selector_add_route_style (rss
, &PCB
->RouteStyle
[i
]);
926 g_signal_connect (G_OBJECT (rss
), "select_style",
927 G_CALLBACK (route_style_changed_cb
), NULL
);
928 g_signal_connect (G_OBJECT (rss
), "style_edited",
929 G_CALLBACK (route_styles_edited_cb
), NULL
);
930 ghid_main_menu_install_route_style_selector
931 (GHID_MAIN_MENU (ghidgui
->menu_bar
),
932 GHID_ROUTE_STYLE_SELECTOR (ghidgui
->route_style_selector
));
936 * ---------------------------------------------------------------
942 GtkWidget
*toolbar_button
;
944 guint toolbar_button_cb_id
;
952 static ModeButton mode_buttons
[] = {
953 {NULL
, NULL
, 0, 0, "via", VIA_MODE
, via
},
954 {NULL
, NULL
, 0, 0, "line", LINE_MODE
, line
},
955 {NULL
, NULL
, 0, 0, "arc", ARC_MODE
, arc
},
956 {NULL
, NULL
, 0, 0, "text", TEXT_MODE
, text
},
957 {NULL
, NULL
, 0, 0, "rectangle", RECTANGLE_MODE
, rect
},
958 {NULL
, NULL
, 0, 0, "polygon", POLYGON_MODE
, poly
},
959 {NULL
, NULL
, 0, 0, "polygonhole", POLYGONHOLE_MODE
, polyhole
},
960 {NULL
, NULL
, 0, 0, "buffer", PASTEBUFFER_MODE
, buf
},
961 {NULL
, NULL
, 0, 0, "remove", REMOVE_MODE
, del
},
962 {NULL
, NULL
, 0, 0, "rotate", ROTATE_MODE
, rot
},
963 {NULL
, NULL
, 0, 0, "insertPoint", INSERTPOINT_MODE
, ins
},
964 {NULL
, NULL
, 0, 0, "thermal", THERMAL_MODE
, thrm
},
965 {NULL
, NULL
, 0, 0, "select", ARROW_MODE
, sel
},
966 {NULL
, NULL
, 0, 0, "lock", LOCK_MODE
, lock
}
969 static gint n_mode_buttons
= G_N_ELEMENTS (mode_buttons
);
972 do_set_mode (int mode
)
975 ghid_mode_cursor (mode
);
976 ghidgui
->settings_mode
= mode
;
980 mode_toolbar_button_toggled_cb (GtkToggleButton
*button
, ModeButton
* mb
)
982 gboolean active
= gtk_toggle_button_get_active (button
);
984 if (mb
->button
!= NULL
)
986 g_signal_handler_block (mb
->button
, mb
->button_cb_id
);
987 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb
->button
), active
);
988 g_signal_handler_unblock (mb
->button
, mb
->button_cb_id
);
992 do_set_mode (mb
->mode
);
996 mode_button_toggled_cb (GtkWidget
* widget
, ModeButton
* mb
)
998 gboolean active
= gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget
));
1000 if (mb
->toolbar_button
!= NULL
)
1002 g_signal_handler_block (mb
->toolbar_button
, mb
->toolbar_button_cb_id
);
1003 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb
->toolbar_button
), active
);
1004 g_signal_handler_unblock (mb
->toolbar_button
, mb
->toolbar_button_cb_id
);
1008 do_set_mode (mb
->mode
);
1012 ghid_mode_buttons_update (void)
1017 for (i
= 0; i
< n_mode_buttons
; ++i
)
1019 mb
= &mode_buttons
[i
];
1020 if (Settings
.Mode
== mb
->mode
)
1022 g_signal_handler_block (mb
->button
, mb
->button_cb_id
);
1023 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb
->button
), TRUE
);
1024 g_signal_handler_unblock (mb
->button
, mb
->button_cb_id
);
1026 g_signal_handler_block (mb
->toolbar_button
, mb
->toolbar_button_cb_id
);
1027 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb
->toolbar_button
), TRUE
);
1028 g_signal_handler_unblock (mb
->toolbar_button
, mb
->toolbar_button_cb_id
);
1035 ghid_pack_mode_buttons (void)
1037 if (ghidgui
->compact_vertical
)
1039 gtk_widget_hide (ghidgui
->mode_buttons_frame
);
1040 gtk_widget_show_all (ghidgui
->mode_toolbar
);
1044 gtk_widget_hide (ghidgui
->mode_toolbar
);
1045 gtk_widget_show_all (ghidgui
->mode_buttons_frame
);
1050 make_mode_buttons_and_toolbar (GtkWidget
**mode_frame
,
1051 GtkWidget
**mode_toolbar
)
1053 GtkToolItem
*tool_item
;
1054 GtkWidget
*vbox
, *hbox
= NULL
;
1057 GSList
*group
= NULL
;
1058 GSList
*toolbar_group
= NULL
;
1062 *mode_toolbar
= gtk_toolbar_new ();
1064 *mode_frame
= gtk_frame_new (NULL
);
1065 vbox
= gtk_vbox_new (FALSE
, 0);
1066 gtk_container_add (GTK_CONTAINER (*mode_frame
), vbox
);
1068 for (i
= 0; i
< n_mode_buttons
; ++i
)
1070 mb
= &mode_buttons
[i
];
1072 /* Create tool button for mode frame */
1073 mb
->button
= gtk_radio_button_new (group
);
1074 group
= gtk_radio_button_get_group (GTK_RADIO_BUTTON (mb
->button
));
1075 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (mb
->button
), FALSE
);
1077 /* Create tool button for toolbar */
1078 mb
->toolbar_button
= gtk_radio_button_new (toolbar_group
);
1079 toolbar_group
= gtk_radio_button_get_group (GTK_RADIO_BUTTON (mb
->toolbar_button
));
1080 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (mb
->toolbar_button
), FALSE
);
1082 /* Pack mode-frame button into the frame */
1083 if ((i
% ghidgui
->n_mode_button_columns
) == 0)
1085 hbox
= gtk_hbox_new (FALSE
, 0);
1086 gtk_box_pack_start (GTK_BOX (vbox
), hbox
, FALSE
, FALSE
, 0);
1088 gtk_box_pack_start (GTK_BOX (hbox
), mb
->button
, FALSE
, FALSE
, 0);
1090 /* Create a container for the toolbar button and add that */
1091 tool_item
= gtk_tool_item_new ();
1092 gtk_container_add (GTK_CONTAINER (tool_item
), mb
->toolbar_button
);
1093 gtk_toolbar_insert (GTK_TOOLBAR (*mode_toolbar
), tool_item
, -1);
1095 /* Load the image for the button, create GtkImage widgets for both
1096 * the grid button and the toolbar button, then pack into the buttons
1098 pixbuf
= gdk_pixbuf_new_from_xpm_data ((const char **) mb
->xpm
);
1099 image
= gtk_image_new_from_pixbuf (pixbuf
);
1100 gtk_container_add (GTK_CONTAINER (mb
->button
), image
);
1101 image
= gtk_image_new_from_pixbuf (pixbuf
);
1102 gtk_container_add (GTK_CONTAINER (mb
->toolbar_button
), image
);
1103 g_object_unref (pixbuf
);
1105 if (strcmp (mb
->name
, "select") == 0)
1107 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb
->button
), TRUE
);
1108 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb
->toolbar_button
), TRUE
);
1112 g_signal_connect (mb
->button
, "toggled",
1113 G_CALLBACK (mode_button_toggled_cb
), mb
);
1114 mb
->toolbar_button_cb_id
=
1115 g_signal_connect (mb
->toolbar_button
, "toggled",
1116 G_CALLBACK (mode_toolbar_button_toggled_cb
), mb
);
1122 * ---------------------------------------------------------------
1124 * ---------------------------------------------------------------
1128 delete_chart_cb (GtkWidget
* widget
, GdkEvent
* event
, GHidPort
* port
)
1130 ghid_config_files_write ();
1131 hid_action ("Quit");
1134 * Return TRUE to keep our app running. A FALSE here would let the
1135 * delete signal continue on and kill our program.
1141 destroy_chart_cb (GtkWidget
* widget
, GHidPort
* port
)
1143 ghid_shutdown_renderer (port
);
1148 get_widget_styles (GtkStyle
**menu_bar_style
,
1149 GtkStyle
**tool_button_style
,
1150 GtkStyle
**tool_button_label_style
)
1152 GtkWidget
*tool_button
;
1153 GtkWidget
*tool_button_label
;
1154 GtkToolItem
*tool_item
;
1156 /* Build a tool item to extract the theme's styling for a toolbar button with text */
1157 tool_item
= gtk_tool_item_new ();
1158 gtk_toolbar_insert (GTK_TOOLBAR (ghidgui
->mode_toolbar
), tool_item
, 0);
1159 tool_button
= gtk_button_new ();
1160 gtk_container_add (GTK_CONTAINER (tool_item
), tool_button
);
1161 tool_button_label
= gtk_label_new ("");
1162 gtk_container_add (GTK_CONTAINER (tool_button
), tool_button_label
);
1164 /* Grab the various styles we need */
1165 gtk_widget_ensure_style (ghidgui
->menu_bar
);
1166 *menu_bar_style
= gtk_widget_get_style (ghidgui
->menu_bar
);
1168 gtk_widget_ensure_style (tool_button
);
1169 *tool_button_style
= gtk_widget_get_style (tool_button
);
1171 gtk_widget_ensure_style (tool_button_label
);
1172 *tool_button_label_style
= gtk_widget_get_style (tool_button_label
);
1174 gtk_widget_destroy (GTK_WIDGET (tool_item
));
1178 do_fix_topbar_theming (void)
1180 GtkWidget
*rel_pos_frame
;
1181 GtkWidget
*abs_pos_frame
;
1182 GtkStyle
*menu_bar_style
;
1183 GtkStyle
*tool_button_style
;
1184 GtkStyle
*tool_button_label_style
;
1186 get_widget_styles (&menu_bar_style
,
1188 &tool_button_label_style
);
1190 /* Style the top bar background as if it were all a menu bar */
1191 gtk_widget_set_style (ghidgui
->top_bar_background
, menu_bar_style
);
1193 /* Style the cursor position labels using the menu bar style as well.
1194 * If this turns out to cause problems with certain gtk themes, we may
1195 * need to grab the GtkStyle associated with an actual menu item to
1196 * get a text color to render with.
1198 gtk_widget_set_style (ghidgui
->cursor_position_relative_label
, menu_bar_style
);
1199 gtk_widget_set_style (ghidgui
->cursor_position_absolute_label
, menu_bar_style
);
1201 /* Style the units button as if it were a toolbar button - hopefully
1202 * this isn't too ugly sitting on a background themed as a menu bar.
1203 * It is unlikely any theme defines colours for a GtkButton sitting on
1206 rel_pos_frame
= gtk_widget_get_parent (ghidgui
->cursor_position_relative_label
);
1207 abs_pos_frame
= gtk_widget_get_parent (ghidgui
->cursor_position_absolute_label
);
1208 gtk_widget_set_style (rel_pos_frame
, menu_bar_style
);
1209 gtk_widget_set_style (abs_pos_frame
, menu_bar_style
);
1210 gtk_widget_set_style (ghidgui
->grid_units_button
, tool_button_style
);
1211 gtk_widget_set_style (ghidgui
->grid_units_label
, tool_button_label_style
);
1214 /* Attempt to produce a conststent style for our extra menu-bar items by
1215 * copying aspects from the menu bar style set by the user's GTK theme.
1216 * Setup signal handlers to update our efforts if the user changes their
1217 * theme whilst we are running.
1220 fix_topbar_theming (void)
1222 GtkSettings
*settings
;
1224 do_fix_topbar_theming ();
1226 settings
= gtk_widget_get_settings (ghidgui
->top_bar_background
);
1227 g_signal_connect (settings
, "notify::gtk-theme-name",
1228 G_CALLBACK (do_fix_topbar_theming
), NULL
);
1229 g_signal_connect (settings
, "notify::gtk-font-name",
1230 G_CALLBACK (do_fix_topbar_theming
), NULL
);
1234 * Create the top_window contents. The config settings should be loaded
1235 * before this is called.
1238 ghid_build_pcb_top_window (void)
1241 GtkWidget
*vbox_main
, *hbox_middle
, *hbox
;
1242 GtkWidget
*vbox
, *frame
;
1244 GHidPort
*port
= &ghid_port
;
1245 GtkWidget
*scrolled
;
1247 window
= gport
->top_window
;
1249 vbox_main
= gtk_vbox_new (FALSE
, 0);
1250 gtk_container_add (GTK_CONTAINER (window
), vbox_main
);
1252 /* -- Top control bar */
1253 ghidgui
->top_bar_background
= gtk_event_box_new ();
1254 gtk_box_pack_start (GTK_BOX (vbox_main
),
1255 ghidgui
->top_bar_background
, FALSE
, FALSE
, 0);
1257 ghidgui
->top_hbox
= gtk_hbox_new (FALSE
, 4);
1258 gtk_container_add (GTK_CONTAINER (ghidgui
->top_bar_background
),
1262 * menu_hbox will be made insensitive when the gui needs
1263 * a modal button GetLocation button press.
1265 ghidgui
->menu_hbox
= gtk_hbox_new (FALSE
, 0);
1266 gtk_box_pack_start (GTK_BOX (ghidgui
->top_hbox
), ghidgui
->menu_hbox
,
1269 ghidgui
->menubar_toolbar_vbox
= gtk_vbox_new (FALSE
, 0);
1270 gtk_box_pack_start (GTK_BOX (ghidgui
->menu_hbox
),
1271 ghidgui
->menubar_toolbar_vbox
, FALSE
, FALSE
, 0);
1273 /* Build layer menus */
1274 ghidgui
->layer_selector
= ghid_layer_selector_new ();
1275 make_layer_buttons (ghidgui
->layer_selector
);
1276 make_virtual_layer_buttons (ghidgui
->layer_selector
);
1277 g_signal_connect (G_OBJECT (ghidgui
->layer_selector
), "select-layer",
1278 G_CALLBACK (layer_selector_select_callback
),
1280 g_signal_connect (G_OBJECT (ghidgui
->layer_selector
), "toggle-layer",
1281 G_CALLBACK (layer_selector_toggle_callback
),
1283 g_signal_connect (G_OBJECT (ghidgui
->layer_selector
), "rename-layer",
1284 G_CALLBACK (layer_selector_rename_callback
),
1286 /* Build main menu */
1287 ghidgui
->menu_bar
= ghid_load_menus ();
1288 gtk_box_pack_start (GTK_BOX (ghidgui
->menubar_toolbar_vbox
),
1289 ghidgui
->menu_bar
, FALSE
, FALSE
, 0);
1291 make_mode_buttons_and_toolbar (&ghidgui
->mode_buttons_frame
,
1292 &ghidgui
->mode_toolbar
);
1293 gtk_box_pack_start (GTK_BOX (ghidgui
->menubar_toolbar_vbox
),
1294 ghidgui
->mode_toolbar
, FALSE
, FALSE
, 0);
1297 ghidgui
->position_hbox
= gtk_hbox_new (FALSE
, 0);
1298 gtk_box_pack_end (GTK_BOX(ghidgui
->top_hbox
),
1299 ghidgui
->position_hbox
, FALSE
, FALSE
, 4);
1301 make_cursor_position_labels (ghidgui
->position_hbox
, port
);
1303 hbox_middle
= gtk_hbox_new (FALSE
, 0);
1304 gtk_box_pack_start (GTK_BOX (vbox_main
), hbox_middle
, TRUE
, TRUE
, 3);
1306 fix_topbar_theming (); /* Must be called after toolbar is created */
1308 /* -- Left control bar */
1310 * This box will be made insensitive when the gui needs
1311 * a modal button GetLocation button press.
1313 ghidgui
->left_toolbar
= gtk_vbox_new (FALSE
, 0);
1314 gtk_box_pack_start (GTK_BOX (hbox_middle
),
1315 ghidgui
->left_toolbar
, FALSE
, FALSE
, 3);
1317 vbox
= ghid_scrolled_vbox (ghidgui
->left_toolbar
, &scrolled
,
1318 GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
);
1319 gtk_box_pack_start (GTK_BOX(vbox
), ghidgui
->layer_selector
,
1322 /* ghidgui->mode_buttons_frame was created above in the call to
1323 * make_mode_buttons_and_toolbar (...);
1325 gtk_box_pack_start (GTK_BOX (ghidgui
->left_toolbar
),
1326 ghidgui
->mode_buttons_frame
, FALSE
, FALSE
, 0);
1328 frame
= gtk_frame_new(NULL
);
1329 gtk_box_pack_end (GTK_BOX (ghidgui
->left_toolbar
), frame
, FALSE
, FALSE
, 0);
1330 vbox
= gtk_vbox_new(FALSE
, 0);
1331 gtk_container_add(GTK_CONTAINER(frame
), vbox
);
1332 hbox
= gtk_hbox_new(FALSE
, 0);
1333 gtk_box_pack_start(GTK_BOX (vbox
), hbox
, FALSE
, FALSE
, 1);
1334 ghidgui
->route_style_selector
= ghid_route_style_selector_new ();
1335 make_route_style_buttons
1336 (GHID_ROUTE_STYLE_SELECTOR (ghidgui
->route_style_selector
));
1337 gtk_box_pack_start(GTK_BOX(hbox
), ghidgui
->route_style_selector
,
1340 ghidgui
->vbox_middle
= gtk_vbox_new (FALSE
, 0);
1341 gtk_box_pack_start (GTK_BOX (hbox_middle
),
1342 ghidgui
->vbox_middle
, TRUE
, TRUE
, 0);
1344 hbox
= gtk_hbox_new (FALSE
, 0);
1345 gtk_box_pack_start (GTK_BOX (ghidgui
->vbox_middle
), hbox
, TRUE
, TRUE
, 0);
1347 /* -- The PCB layout output drawing area */
1349 gport
->drawing_area
= gtk_drawing_area_new ();
1350 ghid_init_drawing_widget (gport
->drawing_area
, gport
);
1352 gtk_widget_add_events (gport
->drawing_area
, GDK_EXPOSURE_MASK
1353 | GDK_LEAVE_NOTIFY_MASK
| GDK_ENTER_NOTIFY_MASK
1354 | GDK_BUTTON_RELEASE_MASK
| GDK_BUTTON_PRESS_MASK
1355 | GDK_KEY_RELEASE_MASK
| GDK_KEY_PRESS_MASK
1356 | GDK_FOCUS_CHANGE_MASK
| GDK_POINTER_MOTION_MASK
1357 | GDK_POINTER_MOTION_HINT_MASK
);
1360 * This is required to get the drawing_area key-press-event. Also the
1361 * enter and button press callbacks grab focus to be sure we have it
1362 * when in the drawing_area.
1364 gtk_widget_set_can_focus (gport
->drawing_area
, TRUE
);
1366 gtk_box_pack_start (GTK_BOX (hbox
), gport
->drawing_area
, TRUE
, TRUE
, 0);
1368 ghidgui
->v_adjustment
= gtk_adjustment_new (0.0, 0.0, 100.0,
1371 gtk_vscrollbar_new (GTK_ADJUSTMENT (ghidgui
->v_adjustment
));
1373 gtk_box_pack_start (GTK_BOX (hbox
), ghidgui
->v_range
, FALSE
, FALSE
, 0);
1375 g_signal_connect (G_OBJECT (ghidgui
->v_adjustment
), "value_changed",
1376 G_CALLBACK (v_adjustment_changed_cb
), ghidgui
);
1378 ghidgui
->h_adjustment
= gtk_adjustment_new (0.0, 0.0, 100.0,
1381 gtk_hscrollbar_new (GTK_ADJUSTMENT (ghidgui
->h_adjustment
));
1382 gtk_box_pack_start (GTK_BOX (ghidgui
->vbox_middle
),
1383 ghidgui
->h_range
, FALSE
, FALSE
, 0);
1385 g_signal_connect (G_OBJECT (ghidgui
->h_adjustment
), "value_changed",
1386 G_CALLBACK (h_adjustment_changed_cb
), ghidgui
);
1388 /* -- The bottom status line label */
1389 ghidgui
->status_line_hbox
= gtk_hbox_new (FALSE
, 0);
1390 gtk_box_pack_start (GTK_BOX (ghidgui
->vbox_middle
),
1391 ghidgui
->status_line_hbox
, FALSE
, FALSE
, 2);
1393 label
= gtk_label_new ("");
1394 gtk_label_set_use_markup (GTK_LABEL (label
), TRUE
);
1395 gtk_box_pack_start (GTK_BOX (ghidgui
->status_line_hbox
), label
, FALSE
,
1397 ghidgui
->status_line_label
= label
;
1399 /* Depending on user setting, the command_combo_box may get packed into
1400 | the status_line_hbox, but it will happen on demand the first time
1401 | the user does a command entry.
1404 g_signal_connect (G_OBJECT (gport
->drawing_area
), "realize",
1405 G_CALLBACK (ghid_port_drawing_realize_cb
),
1407 g_signal_connect (G_OBJECT (gport
->drawing_area
), "expose_event",
1408 G_CALLBACK (ghid_drawing_area_expose_cb
),
1410 g_signal_connect (G_OBJECT (gport
->top_window
), "configure_event",
1411 G_CALLBACK (top_window_configure_event_cb
), port
);
1412 g_signal_connect (gport
->top_window
, "enter-notify-event",
1413 G_CALLBACK (top_window_enter_cb
), port
);
1414 g_signal_connect (G_OBJECT (gport
->drawing_area
), "configure_event",
1415 G_CALLBACK (ghid_port_drawing_area_configure_event_cb
),
1419 /* Mouse and key events will need to be intercepted when PCB needs a
1420 | location from the user.
1423 ghid_interface_input_signals_connect ();
1425 g_signal_connect (G_OBJECT (gport
->drawing_area
), "scroll_event",
1426 G_CALLBACK (ghid_port_window_mouse_scroll_cb
), port
);
1427 g_signal_connect (G_OBJECT (gport
->drawing_area
), "enter_notify_event",
1428 G_CALLBACK (ghid_port_window_enter_cb
), port
);
1429 g_signal_connect (G_OBJECT (gport
->drawing_area
), "leave_notify_event",
1430 G_CALLBACK (ghid_port_window_leave_cb
), port
);
1431 g_signal_connect (G_OBJECT (gport
->drawing_area
), "motion_notify_event",
1432 G_CALLBACK (ghid_port_window_motion_cb
), port
);
1436 g_signal_connect (G_OBJECT (window
), "delete_event",
1437 G_CALLBACK (delete_chart_cb
), port
);
1438 g_signal_connect (G_OBJECT (window
), "destroy",
1439 G_CALLBACK (destroy_chart_cb
), port
);
1441 ghidgui
->creating
= FALSE
;
1443 gtk_widget_show_all (gport
->top_window
);
1444 ghid_pack_mode_buttons ();
1445 gdk_window_set_back_pixmap (gtk_widget_get_window (gport
->drawing_area
),
1450 /* Connect and disconnect just the signals a g_main_loop() will need.
1451 | Cursor and motion events still need to be handled by the top level
1452 | loop, so don't connect/reconnect these.
1453 | A g_main_loop will be running when PCB wants the user to select a
1454 | location or if command entry is needed in the status line hbox.
1455 | During these times normal button/key presses are intercepted, either
1456 | by new signal handlers or the command_combo_box entry.
1458 static gulong button_press_handler
, button_release_handler
,
1459 key_press_handler
, key_release_handler
;
1462 ghid_interface_input_signals_connect (void)
1464 button_press_handler
=
1465 g_signal_connect (G_OBJECT (gport
->drawing_area
), "button_press_event",
1466 G_CALLBACK (ghid_port_button_press_cb
), NULL
);
1468 button_release_handler
=
1469 g_signal_connect (G_OBJECT (gport
->drawing_area
), "button_release_event",
1470 G_CALLBACK (ghid_port_button_release_cb
), NULL
);
1473 g_signal_connect (G_OBJECT (gport
->drawing_area
), "key_press_event",
1474 G_CALLBACK (ghid_port_key_press_cb
), NULL
);
1476 key_release_handler
=
1477 g_signal_connect (G_OBJECT (gport
->drawing_area
), "key_release_event",
1478 G_CALLBACK (ghid_port_key_release_cb
), NULL
);
1482 ghid_interface_input_signals_disconnect (void)
1484 if (button_press_handler
)
1485 g_signal_handler_disconnect (gport
->drawing_area
, button_press_handler
);
1487 if (button_release_handler
)
1488 g_signal_handler_disconnect (gport
->drawing_area
, button_release_handler
);
1490 if (key_press_handler
)
1491 g_signal_handler_disconnect (gport
->drawing_area
, key_press_handler
);
1493 if (key_release_handler
)
1494 g_signal_handler_disconnect (gport
->drawing_area
, key_release_handler
);
1496 button_press_handler
= button_release_handler
= 0;
1497 key_press_handler
= key_release_handler
= 0;
1502 /* We'll set the interface insensitive when a g_main_loop is running so the
1503 | Gtk menus and buttons don't respond and interfere with the special entry
1504 | the user needs to be doing.
1507 ghid_interface_set_sensitive (gboolean sensitive
)
1509 gtk_widget_set_sensitive (ghidgui
->left_toolbar
, sensitive
);
1510 gtk_widget_set_sensitive (ghidgui
->menu_hbox
, sensitive
);
1514 /* ----------------------------------------------------------------------
1515 * initializes icon pixmap and also cursor bit maps
1518 ghid_init_icons (GHidPort
* port
)
1520 GdkWindow
*window
= gtk_widget_get_window (gport
->top_window
);
1522 XC_clock_source
= gdk_bitmap_create_from_data (window
,
1523 (char *) rotateIcon_bits
,
1527 gdk_bitmap_create_from_data (window
, (char *) rotateMask_bits
,
1528 rotateMask_width
, rotateMask_height
);
1530 XC_hand_source
= gdk_bitmap_create_from_data (window
,
1531 (char *) handIcon_bits
,
1535 gdk_bitmap_create_from_data (window
, (char *) handMask_bits
,
1536 handMask_width
, handMask_height
);
1538 XC_lock_source
= gdk_bitmap_create_from_data (window
,
1539 (char *) lockIcon_bits
,
1543 gdk_bitmap_create_from_data (window
, (char *) lockMask_bits
,
1544 lockMask_width
, lockMask_height
);
1548 ghid_create_pcb_widgets (void)
1550 GHidPort
*port
= &ghid_port
;
1554 ghidgui
->bg_pixbuf
= gdk_pixbuf_new_from_file(bg_image_file
, &err
);
1557 g_error("%s", err
->message
);
1560 ghid_build_pcb_top_window ();
1561 ghid_install_accel_groups (GTK_WINDOW (port
->top_window
), ghidgui
);
1562 ghid_update_toggle_flags ();
1564 ghid_init_icons (port
);
1565 SetMode (ARROW_MODE
);
1566 ghid_mode_buttons_update ();
1570 ghid_listener_cb (GIOChannel
*source
,
1571 GIOCondition condition
,
1581 if (condition
& G_IO_HUP
)
1583 gui
->log ("Read end of pipe died!\n");
1587 if (condition
== G_IO_IN
)
1589 status
= g_io_channel_read_line (source
, &str
, &len
, &term
, &err
);
1592 case G_IO_STATUS_NORMAL
:
1593 hid_parse_actions (str
);
1597 case G_IO_STATUS_ERROR
:
1598 gui
->log ("ERROR status from g_io_channel_read_line\n");
1602 case G_IO_STATUS_EOF
:
1603 gui
->log ("Input pipe returned EOF. The --listen option is \n"
1604 "probably not running anymore in this session.\n");
1608 case G_IO_STATUS_AGAIN
:
1609 gui
->log ("AGAIN status from g_io_channel_read_line\n");
1614 fprintf (stderr
, "ERROR: unhandled case in ghid_listener_cb\n");
1621 fprintf (stderr
, "Unknown condition in ghid_listener_cb\n");
1627 ghid_create_listener (void)
1629 GIOChannel
*channel
;
1630 int fd
= fileno (stdin
);
1632 channel
= g_io_channel_unix_new (fd
);
1633 g_io_add_watch (channel
, G_IO_IN
, ghid_listener_cb
, NULL
);
1637 /* ------------------------------------------------------------ */
1639 static int stdin_listen
= 0;
1640 static char *pcbmenu_path
= "gpcb-menu.res";
1642 HID_Attribute ghid_attribute_list
[] = {
1644 /* %start-doc options "21 GTK+ GUI Options"
1647 Listen for actions on stdin.
1651 {"listen", "Listen for actions on stdin",
1652 HID_Boolean
, 0, 0, {0, 0, 0}, 0, &stdin_listen
},
1655 /* %start-doc options "21 GTK+ GUI Options"
1657 @item --bg-image <string>
1658 File name of an image to put into the background of the GUI canvas. The image must
1659 be a color PPM image, in binary (not ASCII) format. It can be any size, and will be
1660 automatically scaled to fit the canvas.
1664 {"bg-image", "Background Image",
1665 HID_String
, 0, 0, {0, 0, 0}, 0, &bg_image_file
},
1666 #define HA_bg_image 1
1668 /* %start-doc options "21 GTK+ GUI Options"
1670 @item --pcb-menu <string>
1671 Location of the @file{gpcb-menu.res} file which defines the menu for the GTK+ GUI.
1675 {"pcb-menu", "Location of gpcb-menu.res file",
1676 HID_String
, 0, 0, {0, PCBLIBDIR
"/gpcb-menu.res", 0}, 0, &pcbmenu_path
}
1677 #define HA_pcbmenu 2
1680 REGISTER_ATTRIBUTES (ghid_attribute_list
)
1683 ghid_get_export_options (int *n_ret
)
1685 *n_ret
= sizeof (ghid_attribute_list
) / sizeof (HID_Attribute
);
1686 return ghid_attribute_list
;
1689 /* Create top level window for routines that will need top_window
1690 | before ghid_create_pcb_widgets() is called.
1693 ghid_parse_arguments (int *argc
, char ***argv
)
1699 /* on windows we need to figure out the installation directory */
1703 tmps
= g_win32_get_package_installation_directory(PACKAGE
"-" VERSION
, NULL
);
1704 #define REST_OF_PATH G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S PACKAGE G_DIR_SEPARATOR_S "newlib"
1705 libdir
= (char *) malloc(strlen(tmps
) +
1706 strlen(REST_OF_PATH
) +
1708 sprintf(libdir
, "%s%s", tmps
, REST_OF_PATH
);
1711 Settings
.LibraryTree
= libdir
;
1718 for (i
= 0; i
< *argc
; i
++)
1720 printf ("ghid_parse_arguments(): *argv[%d] = \"%s\"\n", i
, (*argv
)[i
]);
1724 /* Threads aren't used in PCB, but this call would go here.
1726 /* g_thread_init (NULL); */
1728 #if defined (ENABLE_NLS)
1729 /* Do our own setlocale() stufff since we want to override LC_NUMERIC
1732 setlocale (LC_NUMERIC
, "C"); /* use decimal point instead of comma */
1736 * Prevent gtk_init() and gtk_init_check() from automatically
1737 * calling setlocale (LC_ALL, "") which would undo LC_NUMERIC if ENABLE_NLS
1738 * We also don't want locale set if no ENABLE_NLS to keep "C" LC_NUMERIC.
1740 gtk_disable_setlocale ();
1742 gtk_init (argc
, argv
);
1745 gport
->view
.coord_per_px
= 300.0;
1748 ghid_init_renderer (argc
, argv
, gport
);
1750 ghid_config_files_read (argc
, argv
);
1752 Settings
.AutoPlace
= 0;
1753 for (i
= 0; i
< *argc
; i
++)
1755 if (strcmp ((*argv
)[i
], "-auto-place") == 0)
1756 Settings
.AutoPlace
= 1;
1761 bindtextdomain (PACKAGE
, LOCALEDIR
);
1763 textdomain (PACKAGE
);
1764 bind_textdomain_codeset (PACKAGE
, "UTF-8");
1765 #endif /* ENABLE_NLS */
1767 icon
= gdk_pixbuf_new_from_xpm_data ((const gchar
**) icon_bits
);
1768 gtk_window_set_default_icon (icon
);
1770 window
= gport
->top_window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
1771 gtk_window_set_title (GTK_WINDOW (window
), "PCB");
1772 gtk_window_set_default_size(GTK_WINDOW(window
),
1773 ghidgui
->top_window_width
, ghidgui
->top_window_height
);
1775 if (Settings
.AutoPlace
)
1776 gtk_window_move (GTK_WINDOW (window
), 10, 10);
1778 gtk_widget_show_all (gport
->top_window
);
1779 ghidgui
->creating
= TRUE
;
1783 ghid_do_export (HID_Attr_Val
* options
)
1785 ghid_create_pcb_widgets ();
1787 /* These are needed to make sure the @layerpick and @layerview menus
1788 * are properly initialized and synchronized with the current PCB.
1790 ghid_layer_buttons_update ();
1791 ghid_main_menu_install_route_style_selector
1792 (GHID_MAIN_MENU (ghidgui
->menu_bar
),
1793 GHID_ROUTE_STYLE_SELECTOR (ghidgui
->route_style_selector
));
1796 ghid_create_listener ();
1798 ghid_notify_gui_is_up ();
1801 ghid_config_files_write ();
1805 /*! \brief callback for */
1807 get_layer_visible_cb (int id
)
1810 layer_process (NULL
, NULL
, &visible
, id
);
1815 LayersChanged (int argc
, char **argv
, Coord x
, Coord y
)
1817 if (!ghidgui
|| !ghidgui
->menu_bar
)
1820 ghid_config_groups_changed();
1821 ghid_layer_buttons_update ();
1822 ghid_layer_selector_show_layers
1823 (GHID_LAYER_SELECTOR (ghidgui
->layer_selector
), get_layer_visible_cb
);
1825 /* FIXME - if a layer is moved it should retain its color. But layers
1826 | currently can't do that because color info is not saved in the
1827 | pcb file. So this makes a moved layer change its color to reflect
1828 | the way it will be when the pcb is reloaded.
1830 pcb_colors_from_settings (PCB
);
1834 static const char toggleview_syntax
[] =
1835 "ToggleView(1..MAXLAYER)\n"
1836 "ToggleView(layername)\n"
1837 "ToggleView(Silk|Rats|Pins|Vias|Mask|BackSide)";
1839 static const char toggleview_help
[] =
1840 "Toggle the visibility of the specified layer or layer group.";
1842 /* %start-doc actions ToggleView
1844 If you pass an integer, that layer is specified by index (the first
1845 layer is @code{1}, etc). If you pass a layer name, that layer is
1846 specified by name. When a layer is specified, the visibility of the
1847 layer group containing that layer is toggled.
1849 If you pass a special layer name, the visibility of those components
1850 (silk, rats, etc) is toggled. Note that if you have a layer named
1851 the same as a special layer, the layer is chosen over the special layer.
1856 ToggleView (int argc
, char **argv
, Coord x
, Coord y
)
1861 puts ("Starting ToggleView().");
1868 if (isdigit ((int) argv
[0][0]))
1870 l
= atoi (argv
[0]) - 1;
1872 else if (strcmp (argv
[0], "Silk") == 0)
1873 l
= LAYER_BUTTON_SILK
;
1874 else if (strcmp (argv
[0], "Rats") == 0)
1875 l
= LAYER_BUTTON_RATS
;
1876 else if (strcmp (argv
[0], "Pins") == 0)
1877 l
= LAYER_BUTTON_PINS
;
1878 else if (strcmp (argv
[0], "Vias") == 0)
1879 l
= LAYER_BUTTON_VIAS
;
1880 else if (strcmp (argv
[0], "Mask") == 0)
1881 l
= LAYER_BUTTON_MASK
;
1882 else if (strcmp (argv
[0], "BackSide") == 0)
1883 l
= LAYER_BUTTON_FARSIDE
;
1887 for (i
= 0; i
< max_copper_layer
+ 2; i
++)
1888 if (strcmp (argv
[0], PCB
->Data
->Layer
[i
].Name
) == 0)
1900 /* Now that we've figured out which toggle button ought to control
1901 * this layer, simply hit the button and let the pre-existing code deal
1903 ghid_layer_selector_toggle_layer
1904 (GHID_LAYER_SELECTOR (ghidgui
->layer_selector
), l
);
1908 static const char selectlayer_syntax
[] =
1909 "SelectLayer(1..MAXLAYER|Silk|Rats)";
1911 static const char selectlayer_help
[] =
1912 "Select which layer is the current layer.";
1914 /* %start-doc actions SelectLayer
1916 The specified layer becomes the currently active layer. It is made
1917 visible if it is not already visible
1922 SelectLayer (int argc
, char **argv
, Coord x
, Coord y
)
1927 AFAIL (selectlayer
);
1929 for (i
= 0; i
< max_copper_layer
; ++i
)
1930 if (strcasecmp (argv
[0], PCB
->Data
->Layer
[i
].Name
) == 0)
1933 if (strcasecmp (argv
[0], "silk") == 0)
1934 newl
= LAYER_BUTTON_SILK
;
1935 else if (strcasecmp (argv
[0], "rats") == 0)
1936 newl
= LAYER_BUTTON_RATS
;
1937 else if (newl
== -1)
1938 newl
= atoi (argv
[0]) - 1;
1941 printf ("SelectLayer(): newl = %d\n", newl
);
1944 /* Now that we've figured out which radio button ought to select
1945 * this layer, simply hit the button and let the pre-existing code deal
1947 ghid_layer_selector_select_layer
1948 (GHID_LAYER_SELECTOR (ghidgui
->layer_selector
), newl
);
1954 HID_Action gtk_topwindow_action_list
[] = {
1955 {"LayersChanged", 0, LayersChanged
,
1956 layerschanged_help
, layerschanged_syntax
},
1957 {"SelectLayer", 0, SelectLayer
,
1958 selectlayer_help
, selectlayer_syntax
},
1959 {"ToggleView", 0, ToggleView
,
1960 toggleview_help
, toggleview_syntax
}
1963 REGISTER_ACTIONS (gtk_topwindow_action_list
)
1966 * This function is used to check if a specified hotkey in the menu
1967 * resource file is "special". In this case "special" means that gtk
1968 * assigns a particular meaning to it and the normal menu setup will
1969 * never see these key presses. We capture those and feed them back
1970 * into the menu callbacks. This function is called as new
1971 * accelerators are added when the menus are being built
1974 ghid_check_special_key (const char *accel
, GtkAction
*action
,
1975 const Resource
*node
)
1981 if (action
== NULL
|| accel
== NULL
|| *accel
== '\0')
1985 printf ("%s(\"%s\", \"%s\")\n", __FUNCTION__
, accel
, name
);
1989 if (strstr (accel
, "<alt>") )
1991 mods
|= GHID_KEY_ALT
;
1993 if (strstr (accel
, "<ctrl>") )
1995 mods
|= GHID_KEY_CONTROL
;
1997 if (strstr (accel
, "<shift>") )
1999 mods
|= GHID_KEY_SHIFT
;
2003 len
= strlen (accel
);
2005 #define CHECK_KEY(a) ((len >= strlen (a)) && (strcmp (accel + len - strlen (a), (a)) == 0))
2008 if ( CHECK_KEY ("Tab") )
2010 ind
= mods
| GHID_KEY_TAB
;
2012 else if ( CHECK_KEY ("Up") )
2014 ind
= mods
| GHID_KEY_UP
;
2016 else if ( CHECK_KEY ("Down") )
2018 ind
= mods
| GHID_KEY_DOWN
;
2020 else if ( CHECK_KEY ("Left") )
2022 ind
= mods
| GHID_KEY_LEFT
;
2024 else if ( CHECK_KEY ("Right") )
2026 ind
= mods
| GHID_KEY_RIGHT
;
2031 if (ind
>= N_HOTKEY_ACTIONS
)
2033 fprintf (stderr
, "ERROR: overflow of the ghid_hotkey_actions array. Index = %d\n"
2034 "Please report this.\n", ind
);
2038 ghid_hotkey_actions
[ind
].action
= action
;
2039 ghid_hotkey_actions
[ind
].node
= node
;
2041 printf ("Adding \"special\" hotkey to ghid_hotkey_actions[%u] :"
2042 " %s (%s)\n", ind
, accel
, name
);
2047 /*! \brief Finds the gpcb-menu.res file */
2049 get_menu_filename (void)
2052 char *home_pcbmenu
= NULL
;
2054 /* homedir is set by the core */
2057 Message (_("Note: home directory is \"%s\"\n"), homedir
);
2058 home_pcbmenu
= Concat (homedir
, PCB_DIR_SEPARATOR_S
, ".pcb",
2059 PCB_DIR_SEPARATOR_S
, "gpcb-menu.res", NULL
);
2062 Message (_("Warning: could not determine home directory\n"));
2064 if (access ("gpcb-menu.res", R_OK
) == 0)
2065 rv
= strdup ("gpcb-menu.res");
2066 else if (home_pcbmenu
!= NULL
&& (access (home_pcbmenu
, R_OK
) == 0) )
2068 else if (access (pcbmenu_path
, R_OK
) == 0)
2069 rv
= strdup (pcbmenu_path
);
2075 ghid_load_menus (void)
2078 const Resource
*r
= 0, *bir
;
2080 GtkWidget
*menu_bar
= NULL
;
2083 for (i
= 0; i
< N_HOTKEY_ACTIONS
; i
++)
2085 ghid_hotkey_actions
[i
].action
= NULL
;
2086 ghid_hotkey_actions
[i
].node
= NULL
;
2089 bir
= resource_parse (0, gpcb_menu_default
);
2092 fprintf (stderr
, _("Error: internal menu resource didn't parse\n"));
2096 filename
= get_menu_filename ();
2099 Message ("Loading menus from %s\n", filename
);
2100 r
= resource_parse (filename
, 0);
2105 Message ("Using default menus\n");
2110 mr
= resource_subres (r
, "MainMenu");
2112 mr
= resource_subres (bir
, "MainMenu");
2116 menu_bar
= ghid_main_menu_new (G_CALLBACK (ghid_menu_cb
),
2117 ghid_check_special_key
);
2118 ghid_main_menu_add_resource (GHID_MAIN_MENU (menu_bar
), mr
);
2121 mr
= resource_subres (r
, "PopupMenus");
2123 mr
= resource_subres (bir
, "PopupMenus");
2128 for (i
= 0; i
< mr
->c
; i
++)
2129 if (resource_type (mr
->v
[i
]) == 101)
2130 /* This is a named resource which defines a popup menu */
2131 ghid_main_menu_add_popup_resource (GHID_MAIN_MENU (menu_bar
),
2132 mr
->v
[i
].name
, mr
->v
[i
].subres
);
2136 puts ("Finished loading menus.");
2139 mr
= resource_subres (r
, "Mouse");
2141 mr
= resource_subres (bir
, "Mouse");
2143 load_mouse_resource (mr
);
2148 /* ------------------------------------------------------------ */
2150 static const char adjuststyle_syntax
[] =
2153 static const char adjuststyle_help
[] =
2154 "Open the window which allows editing of the route styles.";
2156 /* %start-doc actions AdjustStyle
2158 Opens the window which allows editing of the route styles.
2163 AdjustStyle(int argc
, char **argv
, Coord x
, Coord y
)
2166 AFAIL (adjuststyle
);
2168 ghid_route_style_selector_edit_dialog
2169 (GHID_ROUTE_STYLE_SELECTOR (ghidgui
->route_style_selector
));
2173 /* ------------------------------------------------------------ */
2175 static const char editlayergroups_syntax
[] =
2176 "EditLayerGroups()\n";
2178 static const char editlayergroups_help
[] =
2179 "Open the preferences window which allows editing of the layer groups.";
2181 /* %start-doc actions EditLayerGroups
2183 Opens the preferences window which is where the layer groups
2184 are edited. This action is primarily provides to provide menu
2185 resource compatibility with the lesstif HID.
2190 EditLayerGroups(int argc
, char **argv
, Coord x
, Coord y
)
2194 AFAIL (editlayergroups
);
2196 hid_actionl ("DoWindows", "Preferences", NULL
);
2201 /* ------------------------------------------------------------ */
2203 HID_Action ghid_menu_action_list
[] = {
2204 {"AdjustStyle", 0, AdjustStyle
, adjuststyle_help
, adjuststyle_syntax
},
2205 {"EditLayerGroups", 0, EditLayerGroups
, editlayergroups_help
, editlayergroups_syntax
}
2208 REGISTER_ACTIONS (ghid_menu_action_list
)