pcb 4.1.1
An interactive printed circuit board layout editor.

gtkhid-main.c

Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include "config.h"
00003 #endif
00004 
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #ifdef HAVE_STRING_H
00008 #include <string.h>
00009 #endif
00010 #include <math.h>
00011 #include <time.h>
00012 
00013 
00014 #include "action.h"
00015 #include "crosshair.h"
00016 #include "error.h"
00017 #include "../hidint.h"
00018 #include "gui.h"
00019 #include "hid/common/hidnogui.h"
00020 #include "hid/common/draw_helpers.h"
00021 #include "pcb-printf.h"
00022 
00023 #ifdef HAVE_LIBDMALLOC
00024 #include <dmalloc.h>
00025 #endif
00026 
00027 static void
00028 pan_common (GHidPort *port)
00029 {
00030   /* Don't pan so far the board is completely off the screen */
00031   port->view.x0 = MAX (-port->view.width,  port->view.x0);
00032   port->view.y0 = MAX (-port->view.height, port->view.y0);
00033   port->view.x0 = MIN ( port->view.x0, PCB->MaxWidth);
00034   port->view.y0 = MIN ( port->view.y0, PCB->MaxHeight);
00035 
00036   ghidgui->adjustment_changed_holdoff = TRUE;
00037   gtk_range_set_value (GTK_RANGE (ghidgui->h_range), port->view.x0);
00038   gtk_range_set_value (GTK_RANGE (ghidgui->v_range), port->view.y0);
00039   ghidgui->adjustment_changed_holdoff = FALSE;
00040 
00041   ghid_port_ranges_changed();
00042 }
00043 
00044 static void
00045 ghid_pan_view_abs (Coord pcb_x, Coord pcb_y, int widget_x, int widget_y)
00046 {
00047   gport->view.x0 = SIDE_X (pcb_x) - widget_x * gport->view.coord_per_px;
00048   gport->view.y0 = SIDE_Y (pcb_y) - widget_y * gport->view.coord_per_px;
00049 
00050   pan_common (gport);
00051 }
00052 
00053 void
00054 ghid_pan_view_rel (Coord dx, Coord dy)
00055 {
00056   gport->view.x0 += dx;
00057   gport->view.y0 += dy;
00058 
00059   pan_common (gport);
00060 }
00061 
00062 
00063 /* gport->view.coord_per_px:
00064  * zoom value is PCB units per screen pixel.  Larger numbers mean zooming
00065  * out - the largest value means you are looking at the whole board.
00066  *
00067  * gport->view_width and gport->view_height are in PCB coordinates
00068  */
00069 
00070 #define ALLOW_ZOOM_OUT_BY 10 /* Arbitrary, and same as the lesstif HID */
00071 static void
00072 ghid_zoom_view_abs (Coord center_x, Coord center_y, double new_zoom)
00073 {
00074   double min_zoom, max_zoom;
00075   double xtmp, ytmp;
00076 
00077   /* Limit the "minimum" zoom constant (maximum zoom), at 1 pixel per PCB
00078    * unit, and set the "maximum" zoom constant (minimum zoom), such that
00079    * the entire board just fits inside the viewport
00080    */
00081   min_zoom = 1;
00082   max_zoom = MAX (PCB->MaxWidth  / gport->width,
00083                   PCB->MaxHeight / gport->height) * ALLOW_ZOOM_OUT_BY;
00084   new_zoom = MIN (MAX (min_zoom, new_zoom), max_zoom);
00085 
00086   if (gport->view.coord_per_px == new_zoom)
00087     return;
00088 
00089   xtmp = (SIDE_X (center_x) - gport->view.x0) / (double)gport->view.width;
00090   ytmp = (SIDE_Y (center_y) - gport->view.y0) / (double)gport->view.height;
00091 
00092   gport->view.coord_per_px = new_zoom;
00093   pixel_slop = new_zoom;
00094   ghid_port_ranges_scale ();
00095 
00096   gport->view.x0 = SIDE_X (center_x) - xtmp * gport->view.width;
00097   gport->view.y0 = SIDE_Y (center_y) - ytmp * gport->view.height;
00098 
00099   pan_common (gport);
00100 
00101   ghid_set_status_line_label ();
00102 }
00103 
00104 static void
00105 ghid_zoom_view_rel (Coord center_x, Coord center_y, double factor)
00106 {
00107   ghid_zoom_view_abs (center_x, center_y, gport->view.coord_per_px * factor);
00108 }
00109 
00110 static void
00111 ghid_zoom_view_fit (void)
00112 {
00113   ghid_pan_view_abs (SIDE_X (0), SIDE_Y (0), 0, 0);
00114   ghid_zoom_view_abs (SIDE_X (0), SIDE_Y (0),
00115                       MAX (PCB->MaxWidth  / gport->width,
00116                            PCB->MaxHeight / gport->height));
00117 }
00118 
00119 static void
00120 ghid_flip_view (Coord center_x, Coord center_y, bool flip_x, bool flip_y)
00121 {
00122   int widget_x, widget_y;
00123 
00124   /* Work out where on the screen the flip point is */
00125   ghid_pcb_to_event_coords (center_x, center_y, &widget_x, &widget_y);
00126 
00127   gport->view.flip_x = gport->view.flip_x != flip_x;
00128   gport->view.flip_y = gport->view.flip_y != flip_y;
00129 
00130   /* Pan the board so the center location remains in the same place */
00131   ghid_pan_view_abs (center_x, center_y, widget_x, widget_y);
00132 
00133   ghid_invalidate_all ();
00134 }
00135 
00136 /* ------------------------------------------------------------ */
00137 
00138 static const char zoom_syntax[] =
00139 "Zoom()\n"
00140 "Zoom(factor)";
00141 
00142 
00143 static const char zoom_help[] =
00144 N_("Various zoom factor changes.");
00145 
00146 /* %start-doc actions Zoom
00147 Changes the zoom (magnification) of the view of the board.  If no
00148 arguments are passed, the view is scaled such that the board just fits
00149 inside the visible window (i.e. ``view all'').  Otherwise,
00150 @var{factor} specifies a change in zoom factor.  It may be prefixed by
00151 @code{+}, @code{-}, or @code{=} to change how the zoom factor is
00152 modified.  The @var{factor} is a floating point number, such as
00153 @code{1.5} or @code{0.75}.
00154 
00155 @table @code
00156   
00157 @item +@var{factor}
00158 Values greater than 1.0 cause the board to be drawn smaller; more of
00159 the board will be visible.  Values between 0.0 and 1.0 cause the board
00160 to be drawn bigger; less of the board will be visible.
00161   
00162 @item -@var{factor}
00163 Values greater than 1.0 cause the board to be drawn bigger; less of
00164 the board will be visible.  Values between 0.0 and 1.0 cause the board
00165 to be drawn smaller; more of the board will be visible.
00166  
00167 @item =@var{factor}
00168  
00169 The @var{factor} is an absolute zoom factor; the unit for this value
00170 is "PCB units per screen pixel".  Since PCB units are 0.01 mil, a
00171 @var{factor} of 1000 means 10 mils (0.01 in) per pixel, or 100 DPI,
00172 about the actual resolution of most screens - resulting in an "actual
00173 size" board.  Similarly, a @var{factor} of 100 gives you a 10x actual
00174 size.
00175  
00176 @end table
00177  
00178 Note that zoom factors of zero are silently ignored.
00179  
00180 
00181 
00182 %end-doc */
00183 
00184 static int
00185 Zoom (int argc, char **argv, Coord x, Coord y)
00186 {
00187   const char *vp;
00188   double v;
00189 
00190   if (argc > 1)
00191     AFAIL (zoom);
00192 
00193   if (argc < 1)
00194     {
00195       ghid_zoom_view_fit ();
00196       return 0;
00197     }
00198 
00199   vp = argv[0];
00200   if (*vp == '+' || *vp == '-' || *vp == '=')
00201     vp++;
00202   v = g_ascii_strtod (vp, 0);
00203   if (v <= 0)
00204     return 1;
00205   switch (argv[0][0])
00206     {
00207     case '-':
00208       ghid_zoom_view_rel (x, y, 1 / v);
00209       break;
00210     default:
00211     case '+':
00212       ghid_zoom_view_rel (x, y, v);
00213       break;
00214     case '=':
00215       ghid_zoom_view_abs (x, y, v);
00216       break;
00217     }
00218 
00219   return 0;
00220 }
00221 
00222 /* ------------------------------------------------------------ */
00223 
00224 void
00225 ghid_calibrate (double xval, double yval)
00226 {
00227   printf (_("ghid_calibrate() -- not implemented\n"));
00228 }
00229 
00230 void
00231 ghid_notify_gui_is_up ()
00232 {
00233   ghidgui->is_up = 1;
00234 }
00235 
00236 int
00237 ghid_shift_is_pressed ()
00238 {
00239   GdkModifierType mask;
00240   GHidPort *out = &ghid_port;
00241 
00242   if (!ghidgui->is_up)
00243     return 0;
00244 
00245   gdk_window_get_pointer (gtk_widget_get_window (out->drawing_area),
00246                           NULL, NULL, &mask);
00247   return (mask & GDK_SHIFT_MASK) ? TRUE : FALSE;
00248 }
00249 
00250 int
00251 ghid_control_is_pressed ()
00252 {
00253   GdkModifierType mask;
00254   GHidPort *out = &ghid_port;
00255 
00256   if (!ghidgui->is_up)
00257     return 0;
00258 
00259   gdk_window_get_pointer (gtk_widget_get_window (out->drawing_area),
00260                           NULL, NULL, &mask);
00261   return (mask & GDK_CONTROL_MASK) ? TRUE : FALSE;
00262 }
00263 
00264 int
00265 ghid_mod1_is_pressed ()
00266 {
00267   GdkModifierType mask;
00268   GHidPort *out = &ghid_port;
00269 
00270   if (!ghidgui->is_up)
00271     return 0;
00272 
00273   gdk_window_get_pointer (gtk_widget_get_window (out->drawing_area),
00274                           NULL, NULL, &mask);
00275 #ifdef __APPLE__
00276   return (mask & ( 1 << 13 ) ) ? TRUE : FALSE;  // The option key is not MOD1, although it should be...
00277 #else
00278   return (mask & GDK_MOD1_MASK) ? TRUE : FALSE;
00279 #endif
00280 }
00281 
00282 void
00283 ghid_set_crosshair (int x, int y, int action)
00284 {
00285   GdkDisplay *display;
00286   GdkScreen *screen;
00287   int offset_x, offset_y;
00288   int widget_x, widget_y;
00289   int pointer_x, pointer_y;
00290   Coord pcb_x, pcb_y;
00291 
00292   if (gport->crosshair_x != x || gport->crosshair_y != y)
00293     {
00294       ghid_set_cursor_position_labels ();
00295       gport->crosshair_x = x;
00296       gport->crosshair_y = y;
00297 
00298       /* FIXME - does this trigger the idle_proc stuff?  It is in the
00299        * lesstif HID.  Maybe something is needed here?
00300        *
00301        * need_idle_proc ();
00302        */
00303     }
00304 
00305   if (action != HID_SC_PAN_VIEWPORT &&
00306       action != HID_SC_WARP_POINTER &&
00307       action != HID_SC_CENTER_IN_VIEWPORT &&
00308       action != HID_SC_CENTER_IN_VIEWPORT_AND_WARP_POINTER)
00309     return;
00310 
00311   /* Find out where the drawing area is on the screen. gdk_display_get_pointer
00312    * and gdk_display_warp_pointer work relative to the whole display, whilst
00313    * our coordinates are relative to the drawing area origin.
00314    */
00315   gdk_window_get_origin (gtk_widget_get_window (gport->drawing_area),
00316                          &offset_x, &offset_y);
00317 
00318   display = gdk_display_get_default ();
00319   screen = gdk_display_get_default_screen (display);
00320 
00321   switch (action) {
00322 
00323     case HID_SC_CENTER_IN_VIEWPORT:
00324 
00325       // Center the viewport on the crosshair
00326       ghid_pan_view_abs (gport->crosshair_x - gport->view.width / 2,
00327                          gport->crosshair_y - gport->view.height / 2,
00328                          0, 0);
00329 
00330       break;
00331 
00332     case HID_SC_CENTER_IN_VIEWPORT_AND_WARP_POINTER:
00333 
00334       // Center the viewport on the crosshair
00335       ghid_pan_view_abs (gport->crosshair_x - gport->view.width / 2,
00336                          gport->crosshair_y - gport->view.height / 2,
00337                          0, 0);
00338   
00339       // We do this to make sure gdk has an up-to-date idea of the widget
00340       // coordinates so gdk_display_warp_pointer will go to the right spot.
00341       gdk_window_process_all_updates ();
00342 
00343       // Warp pointer to crosshair
00344       ghid_pcb_to_event_coords (gport->crosshair_x, gport->crosshair_y,
00345                                 &widget_x, &widget_y);
00346       gdk_display_warp_pointer (display, screen, widget_x + offset_x,
00347                                 widget_y + offset_y);
00348 
00349       break;
00350 
00351     case HID_SC_PAN_VIEWPORT:
00352       /* Pan the board in the viewport so that the crosshair (who's location
00353        * relative on the board was set above) lands where the pointer is.
00354        * We pass the request to pan a particular point on the board to a
00355        * given widget coordinate of the viewport into the rendering code
00356        */
00357 
00358       /* Find out where the pointer is relative to the display */
00359       gdk_display_get_pointer (display, NULL, &pointer_x, &pointer_y, NULL);
00360 
00361       widget_x = pointer_x - offset_x;
00362       widget_y = pointer_y - offset_y;
00363 
00364       ghid_event_to_pcb_coords (widget_x, widget_y, &pcb_x, &pcb_y);
00365       ghid_pan_view_abs (pcb_x, pcb_y, widget_x, widget_y);
00366 
00367       /* Just in case we couldn't pan the board the whole way,
00368        * we warp the pointer to where the crosshair DID land.
00369        */
00370       /* Fall through */
00371 
00372     case HID_SC_WARP_POINTER:
00373       screen = gdk_display_get_default_screen (display);
00374 
00375       ghid_pcb_to_event_coords (x, y, &widget_x, &widget_y);
00376 
00377       pointer_x = offset_x + widget_x;
00378       pointer_y = offset_y + widget_y;
00379 
00380       gdk_display_warp_pointer (display, screen, pointer_x, pointer_y);
00381 
00382       break;
00383   }
00384 }
00385 
00386 typedef struct
00387 {
00388   void (*func) (hidval);
00389   guint id;
00390   hidval user_data;
00391 }
00392 GuiTimer;
00393 
00394   /* We need a wrapper around the hid timer because a gtk timer needs
00395      |  to return FALSE else the timer will be restarted.
00396    */
00397 static gboolean
00398 ghid_timer (GuiTimer * timer)
00399 {
00400   (*timer->func) (timer->user_data);
00401   ghid_mode_cursor (Settings.Mode);
00402   return FALSE;                 /* Turns timer off */
00403 }
00404 
00405 hidval
00406 ghid_add_timer (void (*func) (hidval user_data),
00407                 unsigned long milliseconds, hidval user_data)
00408 {
00409   GuiTimer *timer = g_new0 (GuiTimer, 1);
00410   hidval ret;
00411 
00412   timer->func = func;
00413   timer->user_data = user_data;
00414   timer->id = g_timeout_add (milliseconds, (GSourceFunc) ghid_timer, timer);
00415   ret.ptr = (void *) timer;
00416   return ret;
00417 }
00418 
00419 void
00420 ghid_stop_timer (hidval timer)
00421 {
00422   void *ptr = timer.ptr;
00423 
00424   g_source_remove (((GuiTimer *) ptr)->id);
00425   g_free( ptr );
00426 }
00427 
00428 typedef struct
00429 {
00430   void (*func) ( hidval, int, unsigned int, hidval );
00431   hidval user_data;
00432   int fd;
00433   GIOChannel *channel;
00434   gint id;
00435 }
00436 GuiWatch;
00437 
00438   /* We need a wrapper around the hid file watch to pass the correct flags
00439    */
00440 static gboolean
00441 ghid_watch (GIOChannel *source, GIOCondition condition, gpointer data)
00442 {
00443   unsigned int pcb_condition = 0;
00444   hidval x;
00445   GuiWatch *watch = (GuiWatch*)data;
00446 
00447   if (condition & G_IO_IN)
00448     pcb_condition |= PCB_WATCH_READABLE;
00449   if (condition & G_IO_OUT)
00450     pcb_condition |= PCB_WATCH_WRITABLE;
00451   if (condition & G_IO_ERR)
00452     pcb_condition |= PCB_WATCH_ERROR;
00453   if (condition & G_IO_HUP)
00454     pcb_condition |= PCB_WATCH_HANGUP;
00455 
00456   x.ptr = (void *) watch;
00457   watch->func (x, watch->fd, pcb_condition, watch->user_data);
00458   ghid_mode_cursor (Settings.Mode);
00459 
00460   return TRUE;  /* Leave watch on */
00461 }
00462 
00463 hidval
00464 ghid_watch_file (int fd, unsigned int condition, void (*func) (hidval watch, int fd, unsigned int condition, hidval user_data),
00465   hidval user_data)
00466 {
00467   GuiWatch *watch = g_new0 (GuiWatch, 1);
00468   hidval ret;
00469   unsigned int glib_condition = 0;
00470 
00471   if (condition & PCB_WATCH_READABLE)
00472     glib_condition |= G_IO_IN;
00473   if (condition & PCB_WATCH_WRITABLE)
00474     glib_condition |= G_IO_OUT;
00475   if (condition & PCB_WATCH_ERROR)
00476     glib_condition |= G_IO_ERR;
00477   if (condition & PCB_WATCH_HANGUP)
00478     glib_condition |= G_IO_HUP;
00479 
00480   watch->func = func;
00481   watch->user_data = user_data;
00482   watch->fd = fd;
00483   watch->channel = g_io_channel_unix_new( fd );
00484   watch->id = g_io_add_watch( watch->channel, (GIOCondition)glib_condition, ghid_watch, watch );
00485 
00486   ret.ptr = (void *) watch;
00487   return ret;
00488 }
00489 
00490 void
00491 ghid_unwatch_file (hidval data)
00492 {
00493   GuiWatch *watch = (GuiWatch*)data.ptr;
00494 
00495   g_io_channel_shutdown( watch->channel, TRUE, NULL ); 
00496   g_io_channel_unref( watch->channel );
00497   g_free( watch );
00498 }
00499 
00500 typedef struct
00501 {
00502   GSource source;
00503   void (*func) (hidval user_data);
00504   hidval user_data; 
00505 } BlockHookSource;
00506 
00507 static gboolean ghid_block_hook_prepare  (GSource     *source,
00508                                              gint     *timeout);
00509 static gboolean ghid_block_hook_check    (GSource     *source);
00510 static gboolean ghid_block_hook_dispatch (GSource     *source,
00511                                           GSourceFunc  callback,
00512                                           gpointer     user_data);
00513 
00514 static GSourceFuncs ghid_block_hook_funcs = {
00515   ghid_block_hook_prepare,
00516   ghid_block_hook_check,
00517   ghid_block_hook_dispatch,
00518   NULL // No destroy notification
00519 };
00520 
00521 static gboolean
00522 ghid_block_hook_prepare (GSource *source,
00523                          gint    *timeout)
00524 {
00525   hidval data = ((BlockHookSource *)source)->user_data;
00526   ((BlockHookSource *)source)->func( data );
00527   return FALSE;
00528 }
00529 
00530 static gboolean
00531 ghid_block_hook_check (GSource *source)
00532 {
00533   return FALSE;
00534 }
00535 
00536 static gboolean
00537 ghid_block_hook_dispatch (GSource     *source,
00538                           GSourceFunc  callback,
00539                           gpointer     user_data)
00540 {
00541   return FALSE;
00542 }
00543 
00544 static hidval
00545 ghid_add_block_hook (void (*func) (hidval data),
00546                      hidval user_data)
00547 {
00548   hidval ret;
00549   BlockHookSource *source;
00550 
00551   source = (BlockHookSource *)g_source_new (&ghid_block_hook_funcs, sizeof( BlockHookSource ));
00552 
00553   source->func = func;
00554   source->user_data = user_data;
00555 
00556   g_source_attach ((GSource *)source, NULL);
00557 
00558   ret.ptr = (void *) source;
00559   return ret;
00560 }
00561 
00562 static void
00563 ghid_stop_block_hook (hidval mlpoll)
00564 {
00565   GSource *source = (GSource *)mlpoll.ptr;
00566   g_source_destroy( source );
00567 }
00568 
00569 int
00570 ghid_confirm_dialog (char *msg, ...)
00571 {
00572   int rv = 0;
00573   va_list ap;
00574   char *cancelmsg = NULL, *okmsg = NULL;
00575   static gint x = -1, y = -1;
00576   GtkWidget *dialog;
00577   GHidPort *out = &ghid_port;
00578 
00579   va_start (ap, msg);
00580   cancelmsg = va_arg (ap, char *);
00581   okmsg = va_arg (ap, char *);
00582   va_end (ap);
00583 
00584   if (!cancelmsg)
00585     {
00586       cancelmsg = _("_Cancel");
00587       okmsg = _("_OK");
00588     }
00589 
00590   dialog = gtk_message_dialog_new (GTK_WINDOW (out->top_window),
00591                                    (GtkDialogFlags) (GTK_DIALOG_MODAL |
00592                                                      GTK_DIALOG_DESTROY_WITH_PARENT),
00593                                    GTK_MESSAGE_QUESTION,
00594                                    GTK_BUTTONS_NONE,
00595                                    "%s", msg);
00596   gtk_dialog_add_button (GTK_DIALOG (dialog), 
00597                           cancelmsg, GTK_RESPONSE_CANCEL);
00598   if (okmsg)
00599     {
00600       gtk_dialog_add_button (GTK_DIALOG (dialog), 
00601                              okmsg, GTK_RESPONSE_OK);
00602     }
00603 
00604   if(x != -1) {
00605         gtk_window_move(GTK_WINDOW (dialog), x, y);
00606   }
00607 
00608   if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
00609     rv = 1;
00610 
00611   gtk_window_get_position(GTK_WINDOW (dialog), &x, &y);
00612 
00613   gtk_widget_destroy (dialog);
00614   return rv;
00615 }
00616 
00617 int
00618 ghid_close_confirm_dialog ()
00619 {
00620   switch (ghid_dialog_close_confirm ())
00621     {
00622     case GUI_DIALOG_CLOSE_CONFIRM_SAVE:
00623       {
00624         if (hid_actionl ("Save", NULL))
00625           { /* Save failed */
00626             return 0; /* Cancel */
00627           } else {
00628             return 1; /* Close */
00629           }
00630       }
00631     case GUI_DIALOG_CLOSE_CONFIRM_NOSAVE:
00632       {
00633         return 1; /* Close */
00634       }
00635     case GUI_DIALOG_CLOSE_CONFIRM_CANCEL:
00636     default:
00637       {
00638         return 0; /* Cancel */
00639       }
00640     }
00641 }
00642 
00643 void
00644 ghid_report_dialog (char *title, char *msg)
00645 {
00646   ghid_dialog_report (title, msg);
00647 }
00648 
00649 char *
00650 ghid_prompt_for (const char *msg, const char *default_string)
00651 {
00652   char *rv;
00653 
00654   rv = ghid_dialog_input (msg, default_string);
00655   return rv;
00656 }
00657 
00658 /* FIXME -- implement a proper file select dialog */
00659 #ifdef FIXME
00660 char *
00661 ghid_fileselect (const char *title, const char *descr,
00662                  char *default_file, char *default_ext,
00663                  const char *history_tag, int flags)
00664 {
00665   char *rv;
00666 
00667   rv = ghid_dialog_input (title, default_file);
00668   return rv;
00669 }
00670 #endif
00671 
00672 void
00673 ghid_show_item (void *item)
00674 {
00675   ghid_pinout_window_show (&ghid_port, (ElementType *) item);
00676 }
00677 
00678 void
00679 ghid_beep ()
00680 {
00681   gdk_beep ();
00682 }
00683 
00684 struct progress_dialog
00685 {
00686   GtkWidget *dialog;
00687   GtkWidget *message;
00688   GtkWidget *progress;
00689   gint response_id;
00690   GMainLoop *loop;
00691   gboolean destroyed;
00692   gboolean started;
00693   GTimer *timer;
00694 
00695   gulong response_handler;
00696   gulong destroy_handler;
00697   gulong delete_handler;
00698 };
00699 
00700 static void
00701 run_response_handler (GtkDialog *dialog,
00702                       gint response_id,
00703                       gpointer data)
00704 {
00705   struct progress_dialog *pd = data;
00706 
00707   pd->response_id = response_id;
00708 }
00709 
00710 static gint
00711 run_delete_handler (GtkDialog *dialog,
00712                     GdkEventAny *event,
00713                     gpointer data)
00714 {
00715   struct progress_dialog *pd = data;
00716 
00717   pd->response_id = GTK_RESPONSE_DELETE_EVENT;
00718 
00719   return TRUE; /* Do not destroy */
00720 }
00721 
00722 static void
00723 run_destroy_handler (GtkDialog *dialog, gpointer data)
00724 {
00725   struct progress_dialog *pd = data;
00726 
00727   pd->destroyed = TRUE;
00728 }
00729 
00730 static struct progress_dialog *
00731 make_progress_dialog (void)
00732 {
00733   struct progress_dialog *pd;
00734   GtkWidget *content_area;
00735   GtkWidget *alignment;
00736   GtkWidget *vbox;
00737 
00738   pd = g_new0 (struct progress_dialog, 1);
00739   pd->response_id = GTK_RESPONSE_NONE;
00740 
00741   pd->dialog = gtk_dialog_new_with_buttons (_("Progress"),
00742                                             GTK_WINDOW (gport->top_window),
00743                                             /* Modal so nothing else can get events whilst
00744                                                the main mainloop isn't running */
00745                                             GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
00746                                             GTK_STOCK_CANCEL,
00747                                             GTK_RESPONSE_CANCEL,
00748                                             NULL);
00749 
00750   gtk_window_set_deletable (GTK_WINDOW (pd->dialog), FALSE);
00751   gtk_window_set_skip_pager_hint (GTK_WINDOW (pd->dialog), TRUE);
00752   gtk_window_set_skip_taskbar_hint (GTK_WINDOW (pd->dialog), TRUE);
00753   gtk_widget_set_size_request (pd->dialog, 300, -1);
00754 
00755   pd->message = gtk_label_new (NULL);
00756   gtk_misc_set_alignment (GTK_MISC (pd->message), 0., 0.);
00757 
00758   pd->progress = gtk_progress_bar_new ();
00759   gtk_widget_set_size_request (pd->progress, -1, 26);
00760 
00761   vbox = gtk_vbox_new (false, 0);
00762   gtk_box_pack_start (GTK_BOX (vbox), pd->message, true, true, 8);
00763   gtk_box_pack_start (GTK_BOX (vbox), pd->progress, false, true, 8);
00764 
00765   alignment = gtk_alignment_new (0., 0., 1., 1.);
00766   gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 8, 8, 8, 8);
00767   gtk_container_add (GTK_CONTAINER (alignment), vbox);
00768 
00769   content_area = gtk_dialog_get_content_area (GTK_DIALOG (pd->dialog));
00770   gtk_box_pack_start (GTK_BOX (content_area), alignment, true, true, 0);
00771 
00772   gtk_widget_show_all (alignment);
00773 
00774   g_object_ref (pd->dialog);
00775   gtk_window_present (GTK_WINDOW (pd->dialog));
00776 
00777   pd->response_handler =
00778     g_signal_connect (pd->dialog, "response",
00779                       G_CALLBACK (run_response_handler), pd);
00780   pd->delete_handler =
00781     g_signal_connect (pd->dialog, "delete-event",
00782                       G_CALLBACK (run_delete_handler), pd);
00783   pd->destroy_handler =
00784     g_signal_connect (pd->dialog, "destroy",
00785                       G_CALLBACK (run_destroy_handler), pd);
00786 
00787   pd->loop = g_main_loop_new (NULL, FALSE);
00788   pd->timer = g_timer_new ();
00789 
00790   return pd;
00791 }
00792 
00793 static void
00794 destroy_progress_dialog (struct progress_dialog *pd)
00795 {
00796   if (pd == NULL)
00797     return;
00798 
00799   if (!pd->destroyed)
00800     {
00801       g_signal_handler_disconnect (pd->dialog, pd->response_handler);
00802       g_signal_handler_disconnect (pd->dialog, pd->delete_handler);
00803       g_signal_handler_disconnect (pd->dialog, pd->destroy_handler);
00804     }
00805 
00806   g_timer_destroy (pd->timer);
00807   g_object_unref (pd->dialog);
00808   g_main_loop_unref (pd->loop);
00809 
00810   gtk_widget_destroy (pd->dialog);
00811 
00812   pd->loop = NULL;
00813   g_free (pd);
00814 }
00815 
00816 static void
00817 handle_progress_dialog_events (struct progress_dialog *pd)
00818 {
00819   GMainContext * context = g_main_loop_get_context (pd->loop);
00820 
00821   /* Process events */
00822   while (g_main_context_pending (context))
00823     {
00824       g_main_context_iteration (context, FALSE);
00825     }
00826 }
00827 
00828 #define MIN_TIME_SEPARATION (50./1000.) /* 50ms */
00829 static int
00830 ghid_progress (int so_far, int total, const char *message)
00831 {
00832   static struct progress_dialog *pd = NULL;
00833 
00834   /* If we are finished, destroy any dialog */
00835   if (so_far == 0 && total == 0 && message == NULL)
00836     {
00837       destroy_progress_dialog (pd);
00838       pd = NULL;
00839       return 0;
00840     }
00841 
00842   if (pd == NULL)
00843     pd = make_progress_dialog ();
00844 
00845   /* We don't want to keep the underlying process too busy whilst we
00846    * process events. If we get called quickly after the last progress
00847    * update, wait a little bit before we respond - perhaps the next
00848    * time progress is reported.
00849 
00850    * The exception here is that we always want to process the first
00851    * batch of events after having shown the dialog for the first time
00852    */
00853   if (pd->started && g_timer_elapsed (pd->timer, NULL) < MIN_TIME_SEPARATION)
00854     return 0;
00855 
00856   gtk_label_set_text (GTK_LABEL (pd->message), message);
00857   gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pd->progress),
00858                                  (double)so_far / (double)total);
00859 
00860   handle_progress_dialog_events (pd);
00861   g_timer_start (pd->timer);
00862 
00863   pd->started = TRUE;
00864 
00865   return (pd->response_id == GTK_RESPONSE_CANCEL ||
00866           pd->response_id == GTK_RESPONSE_DELETE_EVENT) ? 1 : 0;
00867 }
00868 
00869 /* ---------------------------------------------------------------------- */
00870 
00871 
00872 typedef struct {
00873   GtkWidget *del;
00874   GtkWidget *w_name;
00875   GtkWidget *w_value;
00876 } AttrRow;
00877 
00878 static AttrRow *attr_row = 0;
00879 static int attr_num_rows = 0;
00880 static int attr_max_rows = 0;
00881 static AttributeListType *attributes_list;
00882 static GtkWidget *attributes_dialog, *attr_table;
00883 
00884 static void attributes_delete_callback (GtkWidget *w, void *v);
00885 
00886 #define GA_RESPONSE_REVERT      1
00887 #define GA_RESPONSE_NEW         2
00888 
00889 static void
00890 ghid_attr_set_table_size ()
00891 {
00892   gtk_table_resize (GTK_TABLE (attr_table), attr_num_rows > 0 ? attr_num_rows : 1, 3);
00893 }
00894 
00895 static void
00896 ghid_attributes_need_rows (int new_max)
00897 {
00898   if (attr_max_rows < new_max)
00899     {
00900       if (attr_row)
00901         attr_row = (AttrRow *) realloc (attr_row, new_max * sizeof(AttrRow));
00902       else
00903         attr_row = (AttrRow *) malloc (new_max * sizeof(AttrRow));
00904     }
00905   while (attr_max_rows < new_max)
00906     {
00907       /* add [attr_max_rows] */
00908       attr_row[attr_max_rows].del = gtk_button_new_with_label (_("del"));
00909       gtk_table_attach (GTK_TABLE (attr_table), attr_row[attr_max_rows].del,
00910                         0, 1,
00911                         attr_max_rows, attr_max_rows+1,
00912                         (GtkAttachOptions)(GTK_FILL | GTK_EXPAND),
00913                         GTK_FILL,
00914                         0, 0);
00915       g_signal_connect (G_OBJECT (attr_row[attr_max_rows].del), "clicked",
00916                         G_CALLBACK (attributes_delete_callback), GINT_TO_POINTER (attr_max_rows) );
00917 
00918       attr_row[attr_max_rows].w_name = gtk_entry_new ();
00919       gtk_table_attach (GTK_TABLE (attr_table), attr_row[attr_max_rows].w_name,
00920                         1, 2,
00921                         attr_max_rows, attr_max_rows+1,
00922                         (GtkAttachOptions)(GTK_FILL | GTK_EXPAND),
00923                         GTK_FILL,
00924                         0, 0);
00925 
00926       attr_row[attr_max_rows].w_value = gtk_entry_new ();
00927       gtk_table_attach (GTK_TABLE (attr_table), attr_row[attr_max_rows].w_value,
00928                         2, 3,
00929                         attr_max_rows, attr_max_rows+1,
00930                         (GtkAttachOptions)(GTK_FILL | GTK_EXPAND),
00931                         GTK_FILL,
00932                         0, 0);
00933 
00934       attr_max_rows ++;
00935     }
00936 
00937   /* Manage any previously unused rows we now need to show.  */
00938   while (attr_num_rows < new_max)
00939     {
00940       /* manage attr_num_rows */
00941       gtk_widget_show (attr_row[attr_num_rows].del);
00942       gtk_widget_show (attr_row[attr_num_rows].w_name);
00943       gtk_widget_show (attr_row[attr_num_rows].w_value);
00944       attr_num_rows ++;
00945     }
00946 }
00947 
00948 static void
00949 ghid_attributes_revert ()
00950 {
00951   int i;
00952 
00953   ghid_attributes_need_rows (attributes_list->Number);
00954 
00955   /* Unmanage any previously used rows we don't need.  */
00956   while (attr_num_rows > attributes_list->Number)
00957     {
00958       attr_num_rows --;
00959       gtk_widget_hide (attr_row[attr_num_rows].del);
00960       gtk_widget_hide (attr_row[attr_num_rows].w_name);
00961       gtk_widget_hide (attr_row[attr_num_rows].w_value);
00962     }
00963 
00964   /* Fill in values */
00965   for (i=0; i<attributes_list->Number; i++)
00966     {
00967       /* create row [i] */
00968       gtk_entry_set_text (GTK_ENTRY (attr_row[i].w_name), attributes_list->List[i].name);
00969       gtk_entry_set_text (GTK_ENTRY (attr_row[i].w_value), attributes_list->List[i].value);
00970 #if 0
00971 #endif
00972     }
00973   ghid_attr_set_table_size ();
00974 }
00975 
00976 static void
00977 attributes_delete_callback (GtkWidget *w, void *v)
00978 {
00979   int i, n;
00980 
00981   n = GPOINTER_TO_INT (v);
00982 
00983   for (i=n; i<attr_num_rows-1; i++)
00984     {
00985       gtk_entry_set_text (GTK_ENTRY (attr_row[i].w_name),
00986                           gtk_entry_get_text (GTK_ENTRY (attr_row[i+1].w_name)));
00987       gtk_entry_set_text (GTK_ENTRY (attr_row[i].w_value),
00988                           gtk_entry_get_text (GTK_ENTRY (attr_row[i+1].w_value)));
00989     }
00990   attr_num_rows --;
00991 
00992   gtk_widget_hide (attr_row[attr_num_rows].del);
00993   gtk_widget_hide (attr_row[attr_num_rows].w_name);
00994   gtk_widget_hide (attr_row[attr_num_rows].w_value);
00995 
00996   ghid_attr_set_table_size ();
00997 }
00998 
00999 static void
01000 ghid_attributes (char *owner, AttributeListType *attrs)
01001 {
01002   GtkWidget *content_area;
01003   int response;
01004 
01005   attributes_list = attrs;
01006 
01007   attr_max_rows = 0;
01008   attr_num_rows = 0;
01009 
01010   attributes_dialog = gtk_dialog_new_with_buttons (owner,
01011                                                    GTK_WINDOW (ghid_port.top_window),
01012                                                    GTK_DIALOG_MODAL,
01013                                                    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
01014                                                    _("Revert"), GA_RESPONSE_REVERT,
01015                                                    _("New"), GA_RESPONSE_NEW,
01016                                                    GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
01017 
01018   attr_table = gtk_table_new (attrs->Number, 3, 0);
01019 
01020   content_area = gtk_dialog_get_content_area (GTK_DIALOG (attributes_dialog));
01021   gtk_box_pack_start (GTK_BOX (content_area), attr_table, FALSE, FALSE, 0);
01022 
01023   gtk_widget_show (attr_table);
01024 
01025   ghid_attributes_revert ();
01026 
01027   while (1)
01028     {
01029       response = gtk_dialog_run (GTK_DIALOG (attributes_dialog));
01030 
01031       if (response == GTK_RESPONSE_CANCEL)
01032         break;
01033 
01034       if (response == GTK_RESPONSE_OK)
01035         {
01036           int i;
01037           /* Copy the values back */
01038           for (i=0; i<attributes_list->Number; i++)
01039             {
01040               if (attributes_list->List[i].name)
01041                 free (attributes_list->List[i].name);
01042               if (attributes_list->List[i].value)
01043                 free (attributes_list->List[i].value);
01044             }
01045           if (attributes_list->Max < attr_num_rows)
01046             {
01047               int sz = attr_num_rows * sizeof (AttributeType);
01048               if (attributes_list->List == NULL)
01049                 attributes_list->List = (AttributeType *) malloc (sz);
01050               else
01051                 attributes_list->List = (AttributeType *) realloc (attributes_list->List, sz);
01052               attributes_list->Max = attr_num_rows;
01053             }
01054           for (i=0; i<attr_num_rows; i++)
01055             {
01056               attributes_list->List[i].name = strdup (gtk_entry_get_text (GTK_ENTRY (attr_row[i].w_name)));
01057               attributes_list->List[i].value = strdup (gtk_entry_get_text (GTK_ENTRY (attr_row[i].w_value)));
01058               attributes_list->Number = attr_num_rows;
01059             }
01060 
01061           break;
01062         }
01063 
01064       if (response == GA_RESPONSE_REVERT)
01065         {
01066           /* Revert */
01067           ghid_attributes_revert ();
01068         }
01069 
01070       if (response == GA_RESPONSE_NEW)
01071         {
01072           ghid_attributes_need_rows (attr_num_rows + 1); /* also bumps attr_num_rows */
01073 
01074           gtk_entry_set_text (GTK_ENTRY (attr_row[attr_num_rows-1].w_name), "");
01075           gtk_entry_set_text (GTK_ENTRY (attr_row[attr_num_rows-1].w_value), "");
01076 
01077           ghid_attr_set_table_size ();
01078         }
01079     }
01080 
01081   gtk_widget_destroy (attributes_dialog);
01082   free (attr_row);
01083   attr_row = NULL;
01084 }
01085 
01086 /* ---------------------------------------------------------------------- */
01087 
01088 HID_DRC_GUI ghid_drc_gui = {
01089   1,                            /* log_drc_overview */
01090   0,                            /* log_drc_details */
01091   ghid_drc_window_reset_message,
01092   ghid_drc_window_append_violation,
01093   ghid_drc_window_throw_dialog,
01094 };
01095 
01096 extern HID_Attribute *ghid_get_export_options (int *);
01097 
01098 
01099 /* ------------------------------------------------------------ 
01100  *
01101  * Actions specific to the GTK HID follow from here
01102  *
01103  */
01104 
01105 
01106 /* ------------------------------------------------------------ */
01107 static const char about_syntax[] =
01108 "About()";
01109 
01110 static const char about_help[] =
01111 N_("Tell the user about this version of PCB.");
01112 
01113 /* %start-doc actions About
01114 
01115 This just pops up an about dialog telling the user which version of
01116 @code{pcb} they're running.
01117 
01118 %end-doc */
01119 
01120 
01121 static int
01122 About (int argc, char **argv, Coord x, Coord y)
01123 {
01124   ghid_dialog_about ();
01125   return 0;
01126 }
01127 
01128 /* ------------------------------------------------------------ */
01129 static const char getxy_syntax[] =
01130 "GetXY()";
01131 
01132 static const char getxy_help[] =
01133 N_("Get a coordinate.");
01134 
01163 /* %start-doc actions GetXY
01164 
01165 Prompts the user for a coordinate, if one is not already selected.
01166 
01167 %end-doc */
01168 
01169 static int
01170 GetXY (int argc, char **argv, Coord x, Coord y)
01171 {
01172   gui->get_coords (argv[0], &x, &y);
01173 
01174   return 0;
01175 }
01176 
01177 /* ---------------------------------------------------------------------- */
01178 
01179 static int PointCursor (int argc, char **argv, Coord x, Coord y)
01180 {
01181   if (!ghidgui)
01182     return 0;
01183 
01184   if (argc > 0)
01185     ghid_point_cursor ();
01186   else
01187     ghid_mode_cursor (Settings.Mode);
01188   return 0;
01189 }
01190 
01191 /* ---------------------------------------------------------------------- */
01192 
01193 static int
01194 RouteStylesChanged (int argc, char **argv, Coord x, Coord y)
01195 {
01196   if (!ghidgui || !ghidgui->route_style_selector)
01197     return 0;
01198 
01199   ghid_route_style_selector_sync
01200     (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector),
01201      Settings.LineThickness, Settings.ViaDrillingHole,
01202      Settings.ViaThickness, Settings.Keepaway);
01203 
01204   return 0;
01205 }
01206 
01207 /* ---------------------------------------------------------------------- */
01208 
01209 int
01210 PCBChanged (int argc, char **argv, Coord x, Coord y)
01211 {
01212   if (!ghidgui)
01213     return 0;
01214 
01215   ghid_window_set_name_label (PCB->Name);
01216 
01217   if (!gport->pixmap)
01218     return 0;
01219 
01220   if (ghidgui->route_style_selector)
01221     {
01222       ghid_route_style_selector_empty
01223         (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
01224       make_route_style_buttons
01225         (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
01226     }
01227   RouteStylesChanged (0, NULL, 0, 0);
01228 
01229   ghid_port_ranges_scale ();
01230   ghid_zoom_view_fit ();
01231   ghid_sync_with_new_layout ();
01232   crosshair_update_range();
01233   return 0;
01234 }
01235 
01236 /* ---------------------------------------------------------------------- */
01237 
01238 static int
01239 LayerGroupsChanged (int argc, char **argv, Coord x, Coord y)
01240 {
01241   printf (_("LayerGroupsChanged -- not implemented\n"));
01242   return 0;
01243 }
01244 
01245 /* ---------------------------------------------------------------------- */
01246 
01247 static int
01248 LibraryChanged (int argc, char **argv, Coord x, Coord y)
01249 {
01250   /* No need to show the library window every time it changes...
01251    *  ghid_library_window_show (&ghid_port, FALSE);
01252    */
01253   return 0;
01254 }
01255 
01256 /* ---------------------------------------------------------------------- */
01257 
01258 static const char command_syntax[] =
01259 "Command()";
01260 
01261 static const char command_help[] =
01262 "Displays the command line input window.";
01263 
01264 /* %start-doc actions Command
01265 
01266 The command window allows the user to manually enter actions to be
01267 executed.
01268 Action syntax can be done one of two ways:
01269 
01270 @itemize @bullet
01271 
01272 @item
01273 Follow the action name by an open parenthesis, arguments separated by
01274 commas, end with a close parenthesis.
01275 Example:
01276 
01277 @example
01278 @code{Abc(1,2,3)}
01279 @end example
01280 
01281 @item
01282 Separate the action name and arguments by spaces.
01283 Example:
01284 
01285 @example
01286 @code{Abc 1 2 3}
01287 @end example
01288 
01289 @end itemize
01290 
01291 The first option allows you to have arguments with spaces in them,
01292 but the second is more ``natural'' to type for most people.
01293 
01294 Note that action names are not case sensitive, but arguments normally
01295 are.  However, most actions will check for ``keywords'' in a case
01296 insensitive way.
01297 
01298 @code{Esc} closes the command window if pressed while the command window has 
01299 focus. If you press the @code{Esc} key, the window goes away without invoking
01300 anything, and the next time you bring up the command window it resumes
01301 entering the command you were entering before.
01302 
01303 %end-doc */
01304 
01305 static int
01306 Command (int argc, char **argv, Coord x, Coord y)
01307 {
01308   ghid_handle_user_command (TRUE);
01309   return 0;
01310 }
01311 
01312 /* ---------------------------------------------------------------------- */
01313 
01314 static const char load_syntax[] =
01315 "Load(Layout|LayoutToBuffer|ElementToBuffer|Netlist|Revert,filename)";
01316 
01317 static const char load_help[] =
01318 N_("Load layout data from a user-selected file.");
01319 
01320 /* %start-doc actions Load
01321 
01322 This action is invoked by typing Load() in the command
01323 entry dialog.
01324 This action is a GUI front-end to the core's @code{LoadFrom}
01325 action (@pxref{LoadFrom Action}).
01326 If you happen to pass a filename, like @code{LoadFrom}, then
01327 @code{LoadFrom} is called directly.
01328 Else this action opens a file chooser dialog window.
01329 The user is to select a filename to load, and then that layout
01330 file is loaded into pcb.
01331 
01332 %end-doc */
01333 
01334 static int
01335 Load (int argc, char **argv, Coord x, Coord y)
01336 {
01337   char *function;
01338   char *name = NULL;
01339 
01340   static gchar *current_element_dir = NULL;
01341   static gchar *current_layout_dir = NULL;
01342   static gchar *current_netlist_dir = NULL;
01343 
01344   /* we've been given the file name */
01345   if (argc > 1)
01346     return hid_actionv ("LoadFrom", argc, argv);
01347 
01348   function = argc ? argv[0] : (char *)"Layout";
01349 
01350   if (strcasecmp (function, "Netlist") == 0)
01351     {
01352       name = ghid_dialog_file_select_open (_("Load netlist file"),
01353                                            &current_netlist_dir,
01354                                            Settings.FilePath);
01355     }
01356   else if (strcasecmp (function, "ElementToBuffer") == 0)
01357     {
01358       name = ghid_dialog_file_select_open (_("Load element to buffer"),
01359                                            &current_element_dir,
01360                                            Settings.LibraryTree);
01361     }
01362   else if (strcasecmp (function, "LayoutToBuffer") == 0)
01363     {
01364       name = ghid_dialog_file_select_open (_("Load layout file to buffer"),
01365                                            &current_layout_dir,
01366                                            Settings.FilePath);
01367     }
01368   else if (strcasecmp (function, "Layout") == 0)
01369     {
01370       name = ghid_dialog_file_select_open (_("Load layout file"),
01371                                            &current_layout_dir,
01372                                            Settings.FilePath);
01373     }
01374 
01375   if (name)
01376     {
01377       if (Settings.verbose)
01378         fprintf (stderr, "%s:  Calling LoadFrom(%s, %s)\n", __FUNCTION__,
01379                  function, name);
01380       hid_actionl ("LoadFrom", function, name, NULL);
01381       g_free (name);
01382     }
01383 
01384   return 0;
01385 }
01386 
01387 
01388 /* ---------------------------------------------------------------------- */
01389 static const char save_syntax[] =
01390 "Save()\n"
01391 "Save(Layout|LayoutAs)\n"
01392 "Save(AllConnections|AllUnusedPins|ElementConnections)\n"
01393 "Save(PasteBuffer)";
01394 
01395 static const char save_help[] =
01396 N_("Save layout and/or element data to a user-selected file.");
01397 
01398 /* %start-doc actions Save
01399 
01400 This action is a GUI front-end to the core's @code{SaveTo} action
01401 (@pxref{SaveTo Action}).  If you happen to pass a filename, like
01402 @code{SaveTo}, then @code{SaveTo} is called directly.  Else, the
01403 user is prompted for a filename to save, and then @code{SaveTo} is
01404 called with that filename.
01405 
01406 %end-doc */
01407 
01408 static int
01409 Save (int argc, char **argv, Coord x, Coord y)
01410 {
01411   char *function;
01412   char *name;
01413   char *prompt;
01414 
01415   static gchar *current_dir = NULL;
01416 
01417   if (argc > 1)
01418     return hid_actionv ("SaveTo", argc, argv);
01419 
01420   function = argc ? argv[0] : (char *)"Layout";
01421 
01422   if (strcasecmp (function, "Layout") == 0)
01423     if (PCB->Filename)
01424       return hid_actionl ("SaveTo", "Layout", PCB->Filename, NULL);
01425 
01426   if (strcasecmp (function, "PasteBuffer") == 0)
01427     prompt = _("Save element as");
01428   else
01429     prompt = _("Save layout as");
01430   
01431   name = ghid_dialog_file_select_save (prompt,
01432                                        &current_dir,
01433                                        PCB->Filename, Settings.FilePath);
01434   
01435   if (name)
01436     {
01437       if (Settings.verbose)
01438         fprintf (stderr, "%s:  Calling SaveTo(%s, %s)\n", 
01439                  __FUNCTION__, function, name);
01440       
01441       if (strcasecmp (function, "PasteBuffer") == 0)
01442         hid_actionl ("PasteBuffer", "Save", name, NULL);
01443       else
01444         {
01445           /* 
01446            * if we got this far and the function is Layout, then
01447            * we really needed it to be a LayoutAs.  Otherwise 
01448            * ActionSaveTo() will ignore the new file name we
01449            * just obtained.
01450            */
01451           if (strcasecmp (function, "Layout") == 0)
01452             hid_actionl ("SaveTo", "LayoutAs", name, NULL);
01453           else
01454             hid_actionl ("SaveTo", function, name, NULL);
01455         }
01456       g_free (name);
01457     }
01458   else
01459     {
01460       return 1;
01461     }
01462 
01463   return 0;
01464 }
01465 
01466 /* ---------------------------------------------------------------------- */
01467 static const char swapsides_syntax[] =
01468 "SwapSides(|v|h|r)";
01469 
01470 static const char swapsides_help[] =
01471 N_("Swaps the side of the board you're looking at.");
01472 
01473 /* %start-doc actions SwapSides
01474 
01475 This action changes the way you view the board.
01476 
01477 @table @code
01478 
01479 @item v
01480 Flips the board over vertically (up/down).
01481 
01482 @item h
01483 Flips the board over horizontally (left/right), like flipping pages in
01484 a book.
01485 
01486 @item r
01487 Rotates the board 180 degrees without changing sides.
01488 
01489 @end table
01490 
01491 If no argument is given, the board isn't moved but the opposite side
01492 is shown.
01493 
01494 Normally, this action changes which pads and silk layer are drawn as
01495 true silk, and which are drawn as the "invisible" layer.  It also
01496 determines which solder mask you see.
01497 
01498 As a special case, if the layer group for the side you're looking at
01499 is visible and currently active, and the layer group for the opposite
01500 is not visible (i.e. disabled), then this action will also swap which
01501 layer group is visible and active, effectively swapping the ``working
01502 side'' of the board.
01503 
01504 %end-doc */
01505 
01506 
01507 static int
01508 SwapSides (int argc, char **argv, Coord x, Coord y)
01509 {
01510   int active_group = GetLayerGroupNumberByNumber (LayerStack[0]);
01511   int top_group = GetLayerGroupNumberBySide (TOP_SIDE);
01512   int bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
01513   bool top_on = LAYER_PTR (PCB->LayerGroups.Entries[top_group][0])->On;
01514   bool bottom_on = LAYER_PTR (PCB->LayerGroups.Entries[bottom_group][0])->On;
01515 
01516   if (argc > 0)
01517     {
01518       switch (argv[0][0]) {
01519         case 'h':
01520         case 'H':
01521           ghid_flip_view (gport->pcb_x, gport->pcb_y, true, false);
01522           break;
01523         case 'v':
01524         case 'V':
01525           ghid_flip_view (gport->pcb_x, gport->pcb_y, false, true);
01526           break;
01527         case 'r':
01528         case 'R':
01529           ghid_flip_view (gport->pcb_x, gport->pcb_y, true, true);
01530           Settings.ShowBottomSide = !Settings.ShowBottomSide; /* Swapped back below */
01531           break;
01532         default:
01533           return 1;
01534       }
01535     }
01536 
01537   Settings.ShowBottomSide = !Settings.ShowBottomSide;
01538 
01539   if ((active_group == top_group    && top_on    && !bottom_on) ||
01540       (active_group == bottom_group && bottom_on && !top_on))
01541     {
01542       bool new_bottom_vis = Settings.ShowBottomSide;
01543 
01544       ChangeGroupVisibility (PCB->LayerGroups.Entries[top_group][0],
01545                              !new_bottom_vis, !new_bottom_vis);
01546       ChangeGroupVisibility (PCB->LayerGroups.Entries[bottom_group][0],
01547                              new_bottom_vis, new_bottom_vis);
01548     }
01549 
01550   layer_process ( NULL, NULL, NULL, LAYER_BUTTON_SILK );
01551   hid_action ("LayersChanged");
01552 
01553   return 0;
01554 }
01555 
01556 /* ------------------------------------------------------------ */
01557 
01558 static const char print_syntax[] =
01559 "Print()";
01560 
01561 static const char print_help[] =
01562 N_("Print the layout.");
01563 
01564 /* %start-doc actions Print
01565 
01566 This will find the default printing HID, prompt the user for its
01567 options, and print the layout.
01568 
01569 %end-doc */
01570 
01571 static int
01572 Print (int argc, char **argv, Coord x, Coord y)
01573 {
01574   HID **hids;
01575   int i;
01576   HID *printer = NULL;
01577 
01578   hids = hid_enumerate ();
01579   for (i = 0; hids[i]; i++)
01580     {
01581       if (hids[i]->printer)
01582         printer = hids[i];
01583     }
01584 
01585   if (printer == NULL)
01586     {
01587       gui->log (_("Can't find a suitable printer HID\n"));
01588       return -1;
01589     }
01590 
01591   /* check if layout is empty */
01592   if (!IsDataEmpty (PCB->Data))
01593     {
01594       ghid_dialog_print (printer);
01595     }
01596   else
01597     gui->log (_("Can't print empty layout\n"));
01598 
01599   return 0;
01600 }
01601 
01602 
01603 /* ------------------------------------------------------------ */
01604 
01605 static HID_Attribute
01606 printer_calibrate_attrs[] = {
01607   {N_("Enter Values here:"), "",
01608    HID_Label, 0, 0, {0, 0, 0}, 0, 0},
01609   {N_("x-calibration"), N_("X scale for calibrating your printer"),
01610    HID_Real, 0.5, 25, {0, 0, 1.00}, 0, 0},
01611   {N_("y-calibration"), N_("Y scale for calibrating your printer"),
01612    HID_Real, 0.5, 25, {0, 0, 1.00}, 0, 0}
01613 };
01614 static HID_Attr_Val printer_calibrate_values[3];
01615 
01616 static const char printcalibrate_syntax[] =
01617 "PrintCalibrate()";
01618 
01619 static const char printcalibrate_help[] =
01620 N_("Calibrate the printer.");
01621 
01622 /* %start-doc actions PrintCalibrate
01623 
01624 This will print a calibration page, which you would measure and type
01625 the measurements in, so that future printouts will be more precise.
01626 
01627 %end-doc */
01628 
01629 static int
01630 PrintCalibrate (int argc, char **argv, Coord x, Coord y)
01631 {
01632   HID *printer = hid_find_printer ();
01633   printer->calibrate (0.0, 0.0);
01634 
01635   if (gui->attribute_dialog (printer_calibrate_attrs, 3,
01636                              printer_calibrate_values,
01637                              _("Printer Calibration Values"),
01638                              _("Enter calibration values for your printer")))
01639     return 1;
01640   printer->calibrate (printer_calibrate_values[1].real_value,
01641                       printer_calibrate_values[2].real_value);
01642   return 0;
01643 }
01644 
01645 /* ------------------------------------------------------------ */
01646 
01647 static const char export_syntax[] =
01648 "Export()\n";
01649 
01650 static const char export_help[] =
01651 N_("Open the Export dialog window.");
01652 
01653 /* %start-doc actions Export
01654 
01655 This action is invoked by typing Export() in the command
01656 entry dialog.
01657 
01658 @noindent This action opens the Export dialog window.
01659 
01660 %end-doc */
01661 
01662 static int
01663 Export (int argc, char **argv, Coord x, Coord y)
01664 {
01665 
01666   /* check if layout is empty */
01667   if (!IsDataEmpty (PCB->Data))
01668     {
01669       ghid_dialog_export ();
01670     }
01671   else
01672     gui->log (_("Can't export empty layout\n"));
01673 
01674   return 0;
01675 }
01676 
01677 /* ------------------------------------------------------------ */
01678 
01679 static const char benchmark_syntax[] =
01680 "Benchmark()\n";
01681 
01682 static const char benchmark_help[] =
01683 N_("Report the amount of redraws per second.");
01684 
01685 /* %start-doc actions Benchmark
01686 
01687 This action is invoked by typing Benchmark() in the command
01688 entry dialog.
01689 
01690 @noindent This action reports the number of redraws per second on the command
01691 line interface.
01692 
01693 %end-doc */
01694 
01695 static int
01696 Benchmark (int argc, char **argv, Coord x, Coord y)
01697 {
01698   int i = 0;
01699   time_t start, end;
01700   GdkDisplay *display;
01701 
01702   display = gdk_drawable_get_display (gport->drawable);
01703 
01704   gdk_display_sync (display);
01705   time (&start);
01706   do
01707     {
01708       ghid_invalidate_all ();
01709       gdk_window_process_updates (gtk_widget_get_window (gport->drawing_area),
01710                                   FALSE);
01711       time (&end);
01712       i++;
01713     }
01714   while (end - start < 10);
01715 
01716   printf (_("%g redraws per second\n"), (double)i / (double)(end-start));
01717 
01718   return 0;
01719 }
01720 
01721 /* ------------------------------------------------------------ */
01722 
01723 static const char center_syntax[] =
01724 "Center()\n";
01725 
01726 static const char center_help[] =
01727 N_("Moves the pointer to the center of the window.");
01728 
01729 /* %start-doc actions Center
01730 
01731 Move the pointer to the center of the window, but only if it's
01732 currently within the window already.
01733 
01734 %end-doc */
01735 
01736 static int
01737 Center(int argc, char **argv, Coord pcb_x, Coord pcb_y)
01738 {
01739   GdkDisplay *display;
01740   GdkScreen *screen;
01741   int offset_x, offset_y;
01742   int widget_x, widget_y;
01743   int pointer_x, pointer_y;
01744 
01745   if (argc != 0)
01746     AFAIL (center);
01747 
01748   /* Aim to put the given x, y PCB coordinates in the center of the widget */
01749   widget_x = gport->width / 2;
01750   widget_y = gport->height / 2;
01751 
01752   ghid_pan_view_abs (pcb_x, pcb_y, widget_x, widget_y);
01753 
01754   /* Now move the mouse pointer to the place where the board location
01755    * actually ended up.
01756    *
01757    * XXX: Should only do this if we confirm we are inside our window?
01758    */
01759 
01760   ghid_pcb_to_event_coords (pcb_x, pcb_y, &widget_x, &widget_y);
01761   gdk_window_get_origin (gtk_widget_get_window (gport->drawing_area),
01762                          &offset_x, &offset_y);
01763 
01764   pointer_x = offset_x + widget_x;
01765   pointer_y = offset_y + widget_y;
01766 
01767   display = gdk_display_get_default ();
01768   screen = gdk_display_get_default_screen (display);
01769   gdk_display_warp_pointer (display, screen, pointer_x, pointer_y);
01770 
01771   return 0;
01772 }
01773 
01774 /* ------------------------------------------------------------ */
01775 static const char cursor_syntax[] =
01776 "Cursor(Type,DeltaUp,DeltaRight,Units)";
01777 
01778 static const char cursor_help[] =
01779 N_("Move the cursor.");
01780 
01781 /* %start-doc actions Cursor
01782 
01783 This action moves the mouse cursor.  Unlike other actions which take
01784 coordinates, this action's coordinates are always relative to the
01785 user's view of the board.  Thus, a positive @var{DeltaUp} may move the
01786 cursor towards the board origin if the board is inverted.
01787 
01788 Type is one of @samp{Pan} or @samp{Warp}.  @samp{Pan} causes the
01789 viewport to move such that the crosshair is under the mouse cursor.
01790 @samp{Warp} causes the mouse cursor to move to be above the crosshair.
01791 
01792 @var{Units} can be one of the following:
01793 
01794 @table @samp
01795 
01796 @item mil
01797 @itemx mm
01798 The cursor is moved by that amount, in board units.
01799 
01800 @item grid
01801 The cursor is moved by that many grid points.
01802 
01803 @item view
01804 The values are percentages of the viewport's view.  Thus, a pan of
01805 @samp{100} would scroll the viewport by exactly the width of the
01806 current view.
01807 
01808 @item board
01809 The values are percentages of the board size.  Thus, a move of
01810 @samp{50,50} moves you halfway across the board.
01811 
01812 @end table
01813 
01814 %end-doc */
01815 
01816 static int
01817 CursorAction(int argc, char **argv, Coord x, Coord y)
01818 {
01819   UnitList extra_units_x = {
01820     { "grid",  PCB->Grid, 0 },
01821     { "view",  gport->view.width, UNIT_PERCENT },
01822     { "board", PCB->MaxWidth, UNIT_PERCENT },
01823     { "", 0, 0 }
01824   };
01825   UnitList extra_units_y = {
01826     { "grid",  PCB->Grid, 0 },
01827     { "view",  gport->view.height, UNIT_PERCENT },
01828     { "board", PCB->MaxHeight, UNIT_PERCENT },
01829     { "", 0, 0 }
01830   };
01831   int pan_warp = HID_SC_DO_NOTHING;
01832   double dx, dy;
01833 
01834   if (argc != 4)
01835     AFAIL (cursor);
01836 
01837   if (strcasecmp (argv[0], "pan") == 0)
01838     pan_warp = HID_SC_PAN_VIEWPORT;
01839   else if (strcasecmp (argv[0], "warp") == 0)
01840     pan_warp = HID_SC_WARP_POINTER;
01841   else
01842     AFAIL (cursor);
01843 
01844   dx = GetValueEx (argv[1], argv[3], NULL, extra_units_x, "");
01845   if (gport->view.flip_x)
01846     dx = -dx;
01847   dy = GetValueEx (argv[2], argv[3], NULL, extra_units_y, "");
01848   if (!gport->view.flip_y)
01849     dy = -dy;
01850 
01851   EventMoveCrosshair (Crosshair.X + dx, Crosshair.Y + dy);
01852   gui->set_crosshair (Crosshair.X, Crosshair.Y, pan_warp);
01853 
01854   return 0;
01855 }
01856 /* ------------------------------------------------------------ */
01857 
01858 static const char dowindows_syntax[] =
01859 "DoWindows(1|2|3|4|5|6)\n"
01860 "DoWindows(Layout|Library|Log|Netlist|Preferences|DRC)";
01861 
01862 static const char dowindows_help[] =
01863 N_("Open various GUI windows.");
01864 
01865 /* %start-doc actions DoWindows
01866 
01867 @table @code
01868 
01869 @item 1
01870 @itemx Layout
01871 Open the layout window.  Since the layout window is always shown
01872 anyway, this has no effect.
01873 
01874 @item 2
01875 @itemx Library
01876 Open the library window.
01877 
01878 @item 3
01879 @itemx Log
01880 Open the log window.
01881 
01882 @item 4
01883 @itemx Netlist
01884 Open the netlist window.
01885 
01886 @item 5
01887 @itemx Preferences
01888 Open the preferences window.
01889 
01890 @item 6
01891 @itemx DRC
01892 Open the DRC violations window.
01893 
01894 @end table
01895 
01896 %end-doc */
01897 
01898 static int
01899 DoWindows (int argc, char **argv, Coord x, Coord y)
01900 {
01901   char *a = argc == 1 ? argv[0] : (char *)"";
01902 
01903   if (strcmp (a, "1") == 0 || strcasecmp (a, "Layout") == 0)
01904     {
01905     }
01906   else if (strcmp (a, "2") == 0 || strcasecmp (a, "Library") == 0)
01907     {
01908       ghid_library_window_show (gport, TRUE);
01909     }
01910   else if (strcmp (a, "3") == 0 || strcasecmp (a, "Log") == 0)
01911     {
01912       ghid_log_window_show (TRUE);
01913     }
01914   else if (strcmp (a, "4") == 0 || strcasecmp (a, "Netlist") == 0)
01915     {
01916       ghid_netlist_window_show (gport, TRUE);
01917     }
01918   else if (strcmp (a, "5") == 0 || strcasecmp (a, "Preferences") == 0)
01919     {
01920       ghid_config_window_show ();
01921     }
01922   else if (strcmp (a, "6") == 0 || strcasecmp (a, "DRC") == 0)
01923     {
01924       ghid_drc_window_show (TRUE);
01925     }
01926   else
01927     {
01928       AFAIL (dowindows);
01929     }
01930 
01931   return 0;
01932 }
01933 
01934 /* ------------------------------------------------------------ */
01935 static const char setunits_syntax[] =
01936 "SetUnits(mm|mil)";
01937 
01938 static const char setunits_help[] =
01939 N_("Set the default measurement units.");
01940 
01941 /* %start-doc actions SetUnits
01942 
01943 @table @code
01944 
01945 @item mil
01946 Sets the display units to mils (1/1000 inch).
01947 
01948 @item mm
01949 Sets the display units to millimeters.
01950 
01951 @end table
01952 
01953 %end-doc */
01954 
01955 static int
01956 SetUnits (int argc, char **argv, Coord x, Coord y)
01957 {
01958   const Unit *new_unit;
01959   if (argc == 0)
01960     return 0;
01961 
01962   new_unit = get_unit_struct (argv[0]);
01963   if (new_unit != NULL && new_unit->allow != NO_PRINT)
01964     {
01965       Settings.grid_unit = new_unit;
01966       Settings.increments = get_increments_struct (Settings.grid_unit->family);
01967       AttributePut (PCB, "PCB::grid::unit", argv[0]);
01968     }
01969 
01970   ghid_config_handle_units_changed ();
01971 
01972   ghid_set_status_line_label ();
01973 
01974   /* FIXME ?
01975    * lesstif_sizes_reset ();
01976    * lesstif_styles_update_values ();
01977    */
01978   return 0;
01979 }
01980 
01981 /* ------------------------------------------------------------ */
01982 static const char scroll_syntax[] =
01983 "Scroll(up|down|left|right, [div])";
01984 
01985 static const char scroll_help[] =
01986 N_("Scroll the viewport.");
01987 
01988 /* % start-doc actions Scroll
01989 
01990 @item up|down|left|right
01991 Specifies the direction to scroll
01992 
01993 @item div
01994 Optional.  Specifies how much to scroll by.  The viewport is scrolled
01995 by 1/div of what is visible, so div = 1 scrolls a whole page. If not
01996 default is given, div=40.
01997 
01998 %end-doc */
01999 
02000 static int
02001 ScrollAction (int argc, char **argv, Coord x, Coord y)
02002 {
02003   gdouble dx = 0.0, dy = 0.0;
02004   int div = 40;
02005 
02006   if (!ghidgui)
02007     return 0;
02008 
02009   if (argc != 1 && argc != 2)
02010     AFAIL (scroll);
02011 
02012   if (argc == 2)
02013     div = atoi(argv[1]);
02014 
02015   if (strcasecmp (argv[0], "up") == 0)
02016     dy = -gport->view.height / div;
02017   else if (strcasecmp (argv[0], "down") == 0)
02018     dy = gport->view.height / div;
02019   else if (strcasecmp (argv[0], "right") == 0)
02020     dx = gport->view.width / div;
02021   else if (strcasecmp (argv[0], "left") == 0)
02022     dx = -gport->view.width / div;
02023   else
02024     AFAIL (scroll);
02025 
02026   ghid_pan_view_rel (dx, dy);
02027 
02028   return 0;
02029 }
02030 
02031 /* ------------------------------------------------------------ */
02032 static const char pan_syntax[] =
02033 "Pan([thumb], Mode)";
02034 
02035 static const char pan_help[] =
02036 N_("Start or stop panning (Mode = 1 to start, 0 to stop)\n"
02037 "Optional thumb argument is ignored for now in gtk hid.\n");
02038 
02039 /* %start-doc actions Pan
02040 
02041 Start or stop panning.  To start call with Mode = 1, to stop call with
02042 Mode = 0.
02043 
02044 %end-doc */
02045 
02046 static int
02047 PanAction (int argc, char **argv, Coord x, Coord y)
02048 {
02049   int mode;
02050 
02051   if (!ghidgui)
02052     return 0;
02053 
02054   if (argc != 1 && argc != 2)
02055     AFAIL (pan);
02056 
02057   if (argc == 1)
02058     mode = atoi(argv[0]);
02059   else
02060     {
02061       mode = atoi(argv[1]);
02062       Message (_("The gtk gui currently ignores the optional first argument "
02063                "to the Pan action.\nFeel free to provide patches.\n"));
02064     }
02065 
02066   gport->panning = mode;
02067 
02068   return 0;
02069 }
02070 
02071 /* ------------------------------------------------------------ */
02072 static const char popup_syntax[] =
02073 "Popup(MenuName, [Button])";
02074 
02075 static const char popup_help[] =
02076 N_("Bring up the popup menu specified by @code{MenuName}.\n"
02077 "If called by a mouse event then the mouse button number\n"
02078 "must be specified as the optional second argument.");
02079 
02080 /* %start-doc actions Popup
02081 
02082 This just pops up the specified menu.  The menu must have been defined
02083 as a named subresource of the Popups resource in the menu resource
02084 file. The second, optional (and ignored) argument represents the mouse
02085 button number which is triggering the popup.
02086 
02087 %end-doc */
02088 
02089 
02090 static int
02091 Popup (int argc, char **argv, Coord x, Coord y)
02092 {
02093   GtkMenu *menu;
02094 
02095   if (argc != 1 && argc != 2)
02096     AFAIL (popup);
02097 
02098   menu = ghid_main_menu_get_popup (GHID_MAIN_MENU (ghidgui->menu_bar), argv[0]);
02099   if (! GTK_IS_MENU (menu))
02100     {
02101       Message (_("The specified popup menu \"%s\" has not been defined.\n"), argv[0]);
02102       return 1;
02103     }
02104   else
02105     {
02106       ghidgui->in_popup = TRUE;
02107       gtk_widget_grab_focus (ghid_port.drawing_area);
02108       gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0, 
02109                       gtk_get_current_event_time());
02110     }
02111   return 0;
02112 }
02113 /* ------------------------------------------------------------ */
02114 static const char importgui_syntax[] =
02115 "ImportGUI()";
02116 
02117 static const char importgui_help[] =
02118 N_("Asks user which schematics to import into PCB.\n");
02119 
02120 /* %start-doc actions ImportGUI
02121 
02122 Asks user which schematics to import into PCB.
02123 
02124 %end-doc */
02125 
02126 
02127 static int
02128 ImportGUI (int argc, char **argv, Coord x, Coord y)
02129 {
02130     GSList *names = NULL;
02131     gchar *name = NULL;
02132     gchar sname[128];
02133     static gchar *current_layout_dir = NULL;
02134     static int I_am_recursing = 0; 
02135     int rv, nsources;
02136 
02137     if (I_am_recursing)
02138         return 1;
02139 
02140 
02141     names = ghid_dialog_file_select_multiple (_("Load schematics"),
02142                                               &current_layout_dir,
02143                                               Settings.FilePath);
02144 
02145     nsources = 0;
02146     while (names != NULL)
02147       {
02148         name = names->data;
02149 
02150 #ifdef DEBUG
02151         printf("File selected = %s\n", name);
02152 #endif
02153 
02154         snprintf (sname, sizeof (sname), "import::src%d", nsources);
02155         AttributePut (PCB, sname, name);
02156 
02157         g_free (name);
02158         nsources++;
02159         names = g_slist_next (names);
02160       }
02161     g_slist_free (names);
02162 
02163     I_am_recursing = 1;
02164     rv = hid_action ("Import");
02165     I_am_recursing = 0;
02166 
02167     return rv;
02168 }
02169 
02170 /* ------------------------------------------------------------ */
02171 
02172 static const char busy_syntax[] =
02173 "Busy()\n";
02174 
02175 static const char busy_help[] =
02176 N_("Show a busy cursor.");
02177 
02178 /* %start-doc actions Busy
02179 
02180 This action is invoked by the program when there is a waiting state for
02181 the user.
02182 
02183 @noindent This action shows a "watch" like cursor graphic to indicate
02184 the pcb program is chewing on a task taking significant time.
02185 
02186 @noindent The cursor graphic is reset when the task is finished.
02187 
02188 When invoked by the user from the command entry window (no program task
02189 running) the cursor graphic is reset when the user enters a coordinate
02190 (left mouse button click).
02191 
02192 %end-doc */
02193 
02194 static int
02195 Busy (int argc, char **argv, Coord x, Coord y)
02196 {
02197   ghid_watch_cursor ();
02198   return 0;
02199 }
02200 
02201 HID_Action ghid_main_action_list[] = {
02202   {"About", 0, About, about_help, about_syntax},
02203   {"Benchmark", 0, Benchmark, benchmark_help, benchmark_syntax},
02204   {"Busy", 0, Busy, busy_help, busy_syntax},
02205   {"Center", N_("Click on a location to center"), Center, center_help, center_syntax},
02206   {"Command", 0, Command, command_help, command_syntax},
02207   {"Cursor", 0, CursorAction, cursor_help, cursor_syntax},
02208   {"DoWindows", 0, DoWindows, dowindows_help, dowindows_syntax},
02209   {"Export", 0, Export, export_help, export_syntax},
02210   {"GetXY", 0, GetXY, getxy_help, getxy_syntax},
02211   {"ImportGUI", 0, ImportGUI, importgui_help, importgui_syntax},
02212   {"LayerGroupsChanged", 0, LayerGroupsChanged},
02213   {"LibraryChanged", 0, LibraryChanged},
02214   {"Load", 0, Load, load_help, load_syntax},
02215   {"Pan", 0, PanAction, pan_help, pan_syntax},
02216   {"PCBChanged", 0, PCBChanged},
02217   {"PointCursor", 0, PointCursor},
02218   {"Popup", 0, Popup, popup_help, popup_syntax},
02219   {"Print", 0, Print, print_help, print_syntax},
02220   {"PrintCalibrate", 0, PrintCalibrate, printcalibrate_help, printcalibrate_syntax},
02221   {"RouteStylesChanged", 0, RouteStylesChanged},
02222   {"Save", 0, Save, save_help, save_syntax},
02223   {"Scroll", N_("Click on a place to scroll"), ScrollAction, scroll_help, scroll_syntax},
02224   {"SetUnits", 0, SetUnits, setunits_help, setunits_syntax},
02225   {"SwapSides", 0, SwapSides, swapsides_help, swapsides_syntax},
02226   {"Zoom", N_("Click on zoom focus"), Zoom, zoom_help, zoom_syntax}
02227 };
02228 
02229 REGISTER_ACTIONS (ghid_main_action_list)
02230 
02231 
02232 static int
02233 flag_flipx (void *data)
02234 {
02235   return gport->view.flip_x;
02236 }
02237 
02238 static int
02239 flag_flipy (void *data)
02240 {
02241   return gport->view.flip_y;
02242 }
02243 
02244 HID_Flag ghid_main_flag_list[] = {
02245   {"flip_x", flag_flipx, NULL},
02246   {"flip_y", flag_flipy, NULL}
02247 };
02248 
02249 REGISTER_FLAGS (ghid_main_flag_list)
02250 
02251 #include "dolists.h"
02252 
02253 /*
02254  * We will need these for finding the windows installation
02255  * directory.  Without that we can't find our fonts and
02256  * footprint libraries.
02257  */
02258 #ifdef WIN32
02259 #define WIN32_LEAN_AND_MEAN
02260 #include <windows.h>
02261 #include <winreg.h>
02262 #endif
02263 
02264 HID ghid_hid;
02265 HID_DRAW ghid_graphics;
02266 
02267 void
02268 hid_gtk_init ()
02269 {
02270 #ifdef WIN32
02271   char * tmps;
02272   char * share_dir;
02273   char *loader_cache;
02274   size_t buffer_size;
02275   FILE *loader_file;
02276 #endif
02277 
02278 #ifdef WIN32
02279   tmps = g_win32_get_package_installation_directory_of_module (NULL);
02280 #define REST_OF_PATH G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S PACKAGE
02281 #define REST_OF_CACHE G_DIR_SEPARATOR_S "loaders.cache"
02282   buffer_size = strlen (tmps) + strlen (REST_OF_PATH) + 1;
02283   share_dir = (char *)malloc (buffer_size);
02284   snprintf (share_dir, buffer_size, "%s%s", tmps, REST_OF_PATH);
02285 
02286   /* Point to our gdk-pixbuf loader cache.  */
02287   buffer_size = strlen (bindir) + strlen (REST_OF_CACHE) + 1;
02288   loader_cache = (char *)malloc (buffer_size);
02289   snprintf (loader_cache, buffer_size, "%s%s", bindir, REST_OF_CACHE);
02290   loader_file = fopen (loader_cache, "r");
02291   if (loader_file)
02292     {
02293       fclose (loader_file);
02294       g_setenv ("GDK_PIXBUF_MODULE_FILE", loader_cache, TRUE);
02295     }
02296 
02297   free (tmps);
02298 #undef REST_OF_PATH
02299   printf ("\"Share\" installation path is \"%s\"\n", share_dir);
02300   free (share_dir);
02301 #endif
02302 
02303   memset (&ghid_hid, 0, sizeof (HID));
02304   memset (&ghid_graphics, 0, sizeof (HID_DRAW));
02305 
02306   common_nogui_init (&ghid_hid);
02307   common_draw_helpers_init (&ghid_graphics);
02308 
02309   ghid_hid.struct_size              = sizeof (HID);
02310   ghid_hid.name                     = "gtk";
02311   ghid_hid.description              = "Gtk - The Gimp Toolkit";
02312   ghid_hid.gui                      = 1;
02313   ghid_hid.poly_after               = 1;
02314 
02315   ghid_hid.get_export_options       = ghid_get_export_options;
02316   ghid_hid.do_export                = ghid_do_export;
02317   ghid_hid.parse_arguments          = ghid_parse_arguments;
02318   ghid_hid.invalidate_lr            = ghid_invalidate_lr;
02319   ghid_hid.invalidate_all           = ghid_invalidate_all;
02320   ghid_hid.notify_crosshair_change  = ghid_notify_crosshair_change;
02321   ghid_hid.notify_mark_change       = ghid_notify_mark_change;
02322   ghid_hid.set_layer                = ghid_set_layer;
02323 
02324   ghid_hid.calibrate                = ghid_calibrate;
02325   ghid_hid.shift_is_pressed         = ghid_shift_is_pressed;
02326   ghid_hid.control_is_pressed       = ghid_control_is_pressed;
02327   ghid_hid.mod1_is_pressed          = ghid_mod1_is_pressed,
02328   ghid_hid.get_coords               = ghid_get_coords;
02329   ghid_hid.set_crosshair            = ghid_set_crosshair;
02330   ghid_hid.add_timer                = ghid_add_timer;
02331   ghid_hid.stop_timer               = ghid_stop_timer;
02332   ghid_hid.watch_file               = ghid_watch_file;
02333   ghid_hid.unwatch_file             = ghid_unwatch_file;
02334   ghid_hid.add_block_hook           = ghid_add_block_hook;
02335   ghid_hid.stop_block_hook          = ghid_stop_block_hook;
02336 
02337   ghid_hid.log                      = ghid_log;
02338   ghid_hid.logv                     = ghid_logv;
02339   ghid_hid.confirm_dialog           = ghid_confirm_dialog;
02340   ghid_hid.close_confirm_dialog     = ghid_close_confirm_dialog;
02341   ghid_hid.report_dialog            = ghid_report_dialog;
02342   ghid_hid.prompt_for               = ghid_prompt_for;
02343   ghid_hid.fileselect               = ghid_fileselect;
02344   ghid_hid.attribute_dialog         = ghid_attribute_dialog;
02345   ghid_hid.show_item                = ghid_show_item;
02346   ghid_hid.beep                     = ghid_beep;
02347   ghid_hid.progress                 = ghid_progress;
02348   ghid_hid.drc_gui                  = &ghid_drc_gui,
02349   ghid_hid.edit_attributes          = ghid_attributes;
02350 
02351   ghid_hid.request_debug_draw       = ghid_request_debug_draw;
02352   ghid_hid.flush_debug_draw         = ghid_flush_debug_draw;
02353   ghid_hid.finish_debug_draw        = ghid_finish_debug_draw;
02354 
02355   ghid_hid.notify_save_pcb          = ghid_notify_save_pcb;
02356   ghid_hid.notify_filename_changed  = ghid_notify_filename_changed;
02357 
02358   ghid_hid.graphics                 = &ghid_graphics;
02359 
02360   ghid_graphics.make_gc             = ghid_make_gc;
02361   ghid_graphics.destroy_gc          = ghid_destroy_gc;
02362   ghid_graphics.use_mask            = ghid_use_mask;
02363   ghid_graphics.set_color           = ghid_set_color;
02364   ghid_graphics.set_line_cap        = ghid_set_line_cap;
02365   ghid_graphics.set_line_width      = ghid_set_line_width;
02366   ghid_graphics.set_draw_xor        = ghid_set_draw_xor;
02367   ghid_graphics.draw_line           = ghid_draw_line;
02368   ghid_graphics.draw_arc            = ghid_draw_arc;
02369   ghid_graphics.draw_rect           = ghid_draw_rect;
02370   ghid_graphics.fill_circle         = ghid_fill_circle;
02371   ghid_graphics.fill_polygon        = ghid_fill_polygon;
02372   ghid_graphics.fill_rect           = ghid_fill_rect;
02373   
02374   ghid_graphics.draw_grid           = ghid_draw_grid;
02375 
02376   ghid_graphics.draw_pcb_polygon    = common_gui_draw_pcb_polygon;
02377 
02378   hid_register_hid (&ghid_hid);
02379 #include "gtk_lists.h"
02380 }