Convert argument in HID_Flags to (void *) rather than (int)
[geda-pcb/pcjc2.git] / src / hid / gtk / gtkhid-main.c
blobbf1885a188293479a1a63dbfad5644f8cbb96b63
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
5 #include <stdio.h>
6 #include <stdlib.h>
7 #ifdef HAVE_STRING_H
8 #include <string.h>
9 #endif
10 #include <math.h>
11 #include <time.h>
14 #include "action.h"
15 #include "crosshair.h"
16 #include "error.h"
17 #include "../hidint.h"
18 #include "gui.h"
19 #include "hid/common/hidnogui.h"
20 #include "hid/common/draw_helpers.h"
21 #include "pcb-printf.h"
23 #ifdef HAVE_LIBDMALLOC
24 #include <dmalloc.h>
25 #endif
27 static void
28 pan_common (GHidPort *port)
30 int event_x, event_y;
32 /* We need to fix up the PCB coordinates corresponding to the last
33 * event so convert it back to event coordinates temporarily. */
34 ghid_pcb_to_event_coords (gport->pcb_x, gport->pcb_y, &event_x, &event_y);
36 /* Don't pan so far the board is completely off the screen */
37 port->view.x0 = MAX (-port->view.width, port->view.x0);
38 port->view.y0 = MAX (-port->view.height, port->view.y0);
39 port->view.x0 = MIN ( port->view.x0, PCB->MaxWidth);
40 port->view.y0 = MIN ( port->view.y0, PCB->MaxHeight);
42 /* Fix up noted event coordinates to match where we clamped. Alternatively
43 * we could call ghid_note_event_location (NULL); to get a new pointer
44 * location, but this costs us an xserver round-trip (on X11 platforms)
46 ghid_event_to_pcb_coords (event_x, event_y, &gport->pcb_x, &gport->pcb_y);
48 ghidgui->adjustment_changed_holdoff = TRUE;
49 gtk_range_set_value (GTK_RANGE (ghidgui->h_range), gport->view.x0);
50 gtk_range_set_value (GTK_RANGE (ghidgui->v_range), gport->view.y0);
51 ghidgui->adjustment_changed_holdoff = FALSE;
53 ghid_port_ranges_changed();
56 static void
57 ghid_pan_view_abs (Coord pcb_x, Coord pcb_y, int widget_x, int widget_y)
59 gport->view.x0 = SIDE_X (pcb_x) - widget_x * gport->view.coord_per_px;
60 gport->view.y0 = SIDE_Y (pcb_y) - widget_y * gport->view.coord_per_px;
62 pan_common (gport);
65 void
66 ghid_pan_view_rel (Coord dx, Coord dy)
68 gport->view.x0 += dx;
69 gport->view.y0 += dy;
71 pan_common (gport);
75 /* gport->view.coord_per_px:
76 * zoom value is PCB units per screen pixel. Larger numbers mean zooming
77 * out - the largest value means you are looking at the whole board.
79 * gport->view_width and gport->view_height are in PCB coordinates
82 #define ALLOW_ZOOM_OUT_BY 10 /* Arbitrary, and same as the lesstif HID */
83 static void
84 ghid_zoom_view_abs (Coord center_x, Coord center_y, double new_zoom)
86 double min_zoom, max_zoom;
87 double xtmp, ytmp;
89 /* Limit the "minimum" zoom constant (maximum zoom), at 1 pixel per PCB
90 * unit, and set the "maximum" zoom constant (minimum zoom), such that
91 * the entire board just fits inside the viewport
93 min_zoom = 1;
94 max_zoom = MAX (PCB->MaxWidth / gport->width,
95 PCB->MaxHeight / gport->height) * ALLOW_ZOOM_OUT_BY;
96 new_zoom = MIN (MAX (min_zoom, new_zoom), max_zoom);
98 if (gport->view.coord_per_px == new_zoom)
99 return;
101 xtmp = (SIDE_X (center_x) - gport->view.x0) / (double)gport->view.width;
102 ytmp = (SIDE_Y (center_y) - gport->view.y0) / (double)gport->view.height;
104 gport->view.coord_per_px = new_zoom;
105 pixel_slop = new_zoom;
106 ghid_port_ranges_scale ();
108 gport->view.x0 = SIDE_X (center_x) - xtmp * gport->view.width;
109 gport->view.y0 = SIDE_Y (center_y) - ytmp * gport->view.height;
111 pan_common (gport);
113 ghid_set_status_line_label ();
116 static void
117 ghid_zoom_view_rel (Coord center_x, Coord center_y, double factor)
119 ghid_zoom_view_abs (center_x, center_y, gport->view.coord_per_px * factor);
122 static void
123 ghid_zoom_view_fit (void)
125 ghid_pan_view_abs (SIDE_X (0), SIDE_Y (0), 0, 0);
126 ghid_zoom_view_abs (SIDE_X (0), SIDE_Y (0),
127 MAX (PCB->MaxWidth / gport->width,
128 PCB->MaxHeight / gport->height));
131 static void
132 ghid_flip_view (Coord center_x, Coord center_y, bool flip_x, bool flip_y)
134 int widget_x, widget_y;
136 /* Work out where on the screen the flip point is */
137 ghid_pcb_to_event_coords (center_x, center_y, &widget_x, &widget_y);
139 gport->view.flip_x = gport->view.flip_x != flip_x;
140 gport->view.flip_y = gport->view.flip_y != flip_y;
142 /* Pan the board so the center location remains in the same place */
143 ghid_pan_view_abs (center_x, center_y, widget_x, widget_y);
145 ghid_invalidate_all ();
148 /* ------------------------------------------------------------ */
150 static const char zoom_syntax[] =
151 "Zoom()\n"
152 "Zoom(factor)";
155 static const char zoom_help[] =
156 N_("Various zoom factor changes.");
158 /* %start-doc actions Zoom
159 Changes the zoom (magnification) of the view of the board. If no
160 arguments are passed, the view is scaled such that the board just fits
161 inside the visible window (i.e. ``view all''). Otherwise,
162 @var{factor} specifies a change in zoom factor. It may be prefixed by
163 @code{+}, @code{-}, or @code{=} to change how the zoom factor is
164 modified. The @var{factor} is a floating point number, such as
165 @code{1.5} or @code{0.75}.
167 @table @code
169 @item +@var{factor}
170 Values greater than 1.0 cause the board to be drawn smaller; more of
171 the board will be visible. Values between 0.0 and 1.0 cause the board
172 to be drawn bigger; less of the board will be visible.
174 @item -@var{factor}
175 Values greater than 1.0 cause the board to be drawn bigger; less of
176 the board will be visible. Values between 0.0 and 1.0 cause the board
177 to be drawn smaller; more of the board will be visible.
179 @item =@var{factor}
181 The @var{factor} is an absolute zoom factor; the unit for this value
182 is "PCB units per screen pixel". Since PCB units are 0.01 mil, a
183 @var{factor} of 1000 means 10 mils (0.01 in) per pixel, or 100 DPI,
184 about the actual resolution of most screens - resulting in an "actual
185 size" board. Similarly, a @var{factor} of 100 gives you a 10x actual
186 size.
188 @end table
190 Note that zoom factors of zero are silently ignored.
194 %end-doc */
196 static int
197 Zoom (int argc, char **argv, Coord x, Coord y)
199 const char *vp;
200 double v;
202 if (argc > 1)
203 AFAIL (zoom);
205 if (argc < 1)
207 ghid_zoom_view_fit ();
208 return 0;
211 vp = argv[0];
212 if (*vp == '+' || *vp == '-' || *vp == '=')
213 vp++;
214 v = g_ascii_strtod (vp, 0);
215 if (v <= 0)
216 return 1;
217 switch (argv[0][0])
219 case '-':
220 ghid_zoom_view_rel (x, y, 1 / v);
221 break;
222 default:
223 case '+':
224 ghid_zoom_view_rel (x, y, v);
225 break;
226 case '=':
227 ghid_zoom_view_abs (x, y, v);
228 break;
231 return 0;
234 /* ------------------------------------------------------------ */
236 void
237 ghid_calibrate (double xval, double yval)
239 printf (_("ghid_calibrate() -- not implemented\n"));
242 void
243 ghid_notify_gui_is_up ()
245 ghidgui->is_up = 1;
249 ghid_shift_is_pressed ()
251 GdkModifierType mask;
252 GHidPort *out = &ghid_port;
254 if (!ghidgui->is_up)
255 return 0;
257 gdk_window_get_pointer (gtk_widget_get_window (out->drawing_area),
258 NULL, NULL, &mask);
259 return (mask & GDK_SHIFT_MASK) ? TRUE : FALSE;
263 ghid_control_is_pressed ()
265 GdkModifierType mask;
266 GHidPort *out = &ghid_port;
268 if (!ghidgui->is_up)
269 return 0;
271 gdk_window_get_pointer (gtk_widget_get_window (out->drawing_area),
272 NULL, NULL, &mask);
273 return (mask & GDK_CONTROL_MASK) ? TRUE : FALSE;
277 ghid_mod1_is_pressed ()
279 GdkModifierType mask;
280 GHidPort *out = &ghid_port;
282 if (!ghidgui->is_up)
283 return 0;
285 gdk_window_get_pointer (gtk_widget_get_window (out->drawing_area),
286 NULL, NULL, &mask);
287 #ifdef __APPLE__
288 return (mask & ( 1 << 13 ) ) ? TRUE : FALSE; // The option key is not MOD1, although it should be...
289 #else
290 return (mask & GDK_MOD1_MASK) ? TRUE : FALSE;
291 #endif
294 void
295 ghid_set_crosshair (int x, int y, int action)
297 GdkDisplay *display;
298 GdkScreen *screen;
299 int offset_x, offset_y;
300 int widget_x, widget_y;
301 int pointer_x, pointer_y;
302 Coord pcb_x, pcb_y;
304 if (gport->crosshair_x != x || gport->crosshair_y != y)
306 ghid_set_cursor_position_labels ();
307 gport->crosshair_x = x;
308 gport->crosshair_y = y;
310 /* FIXME - does this trigger the idle_proc stuff? It is in the
311 * lesstif HID. Maybe something is needed here?
313 * need_idle_proc ();
317 if (action != HID_SC_PAN_VIEWPORT &&
318 action != HID_SC_WARP_POINTER)
319 return;
321 /* Find out where the drawing area is on the screen. gdk_display_get_pointer
322 * and gdk_display_warp_pointer work relative to the whole display, whilst
323 * our coordinates are relative to the drawing area origin.
325 gdk_window_get_origin (gtk_widget_get_window (gport->drawing_area),
326 &offset_x, &offset_y);
327 display = gdk_display_get_default ();
329 switch (action) {
330 case HID_SC_PAN_VIEWPORT:
331 /* Pan the board in the viewport so that the crosshair (who's location
332 * relative on the board was set above) lands where the pointer is.
333 * We pass the request to pan a particular point on the board to a
334 * given widget coordinate of the viewport into the rendering code
337 /* Find out where the pointer is relative to the display */
338 gdk_display_get_pointer (display, NULL, &pointer_x, &pointer_y, NULL);
340 widget_x = pointer_x - offset_x;
341 widget_y = pointer_y - offset_y;
343 ghid_event_to_pcb_coords (widget_x, widget_y, &pcb_x, &pcb_y);
344 ghid_pan_view_abs (pcb_x, pcb_y, widget_x, widget_y);
346 /* Just in case we couldn't pan the board the whole way,
347 * we warp the pointer to where the crosshair DID land.
349 /* Fall through */
351 case HID_SC_WARP_POINTER:
352 screen = gdk_display_get_default_screen (display);
354 ghid_pcb_to_event_coords (x, y, &widget_x, &widget_y);
356 pointer_x = offset_x + widget_x;
357 pointer_y = offset_y + widget_y;
359 gdk_display_warp_pointer (display, screen, pointer_x, pointer_y);
361 break;
365 typedef struct
367 void (*func) (hidval);
368 guint id;
369 hidval user_data;
371 GuiTimer;
373 /* We need a wrapper around the hid timer because a gtk timer needs
374 | to return FALSE else the timer will be restarted.
376 static gboolean
377 ghid_timer (GuiTimer * timer)
379 (*timer->func) (timer->user_data);
380 ghid_mode_cursor (Settings.Mode);
381 return FALSE; /* Turns timer off */
384 hidval
385 ghid_add_timer (void (*func) (hidval user_data),
386 unsigned long milliseconds, hidval user_data)
388 GuiTimer *timer = g_new0 (GuiTimer, 1);
389 hidval ret;
391 timer->func = func;
392 timer->user_data = user_data;
393 timer->id = g_timeout_add (milliseconds, (GSourceFunc) ghid_timer, timer);
394 ret.ptr = (void *) timer;
395 return ret;
398 void
399 ghid_stop_timer (hidval timer)
401 void *ptr = timer.ptr;
403 g_source_remove (((GuiTimer *) ptr)->id);
404 g_free( ptr );
407 typedef struct
409 void (*func) ( hidval, int, unsigned int, hidval );
410 hidval user_data;
411 int fd;
412 GIOChannel *channel;
413 gint id;
415 GuiWatch;
417 /* We need a wrapper around the hid file watch to pass the correct flags
419 static gboolean
420 ghid_watch (GIOChannel *source, GIOCondition condition, gpointer data)
422 unsigned int pcb_condition = 0;
423 hidval x;
424 GuiWatch *watch = (GuiWatch*)data;
426 if (condition & G_IO_IN)
427 pcb_condition |= PCB_WATCH_READABLE;
428 if (condition & G_IO_OUT)
429 pcb_condition |= PCB_WATCH_WRITABLE;
430 if (condition & G_IO_ERR)
431 pcb_condition |= PCB_WATCH_ERROR;
432 if (condition & G_IO_HUP)
433 pcb_condition |= PCB_WATCH_HANGUP;
435 x.ptr = (void *) watch;
436 watch->func (x, watch->fd, pcb_condition, watch->user_data);
437 ghid_mode_cursor (Settings.Mode);
439 return TRUE; /* Leave watch on */
442 hidval
443 ghid_watch_file (int fd, unsigned int condition, void (*func) (hidval watch, int fd, unsigned int condition, hidval user_data),
444 hidval user_data)
446 GuiWatch *watch = g_new0 (GuiWatch, 1);
447 hidval ret;
448 unsigned int glib_condition = 0;
450 if (condition & PCB_WATCH_READABLE)
451 glib_condition |= G_IO_IN;
452 if (condition & PCB_WATCH_WRITABLE)
453 glib_condition |= G_IO_OUT;
454 if (condition & PCB_WATCH_ERROR)
455 glib_condition |= G_IO_ERR;
456 if (condition & PCB_WATCH_HANGUP)
457 glib_condition |= G_IO_HUP;
459 watch->func = func;
460 watch->user_data = user_data;
461 watch->fd = fd;
462 watch->channel = g_io_channel_unix_new( fd );
463 watch->id = g_io_add_watch( watch->channel, (GIOCondition)glib_condition, ghid_watch, watch );
465 ret.ptr = (void *) watch;
466 return ret;
469 void
470 ghid_unwatch_file (hidval data)
472 GuiWatch *watch = (GuiWatch*)data.ptr;
474 g_io_channel_shutdown( watch->channel, TRUE, NULL );
475 g_io_channel_unref( watch->channel );
476 g_free( watch );
479 typedef struct
481 GSource source;
482 void (*func) (hidval user_data);
483 hidval user_data;
484 } BlockHookSource;
486 static gboolean ghid_block_hook_prepare (GSource *source,
487 gint *timeout);
488 static gboolean ghid_block_hook_check (GSource *source);
489 static gboolean ghid_block_hook_dispatch (GSource *source,
490 GSourceFunc callback,
491 gpointer user_data);
493 static GSourceFuncs ghid_block_hook_funcs = {
494 ghid_block_hook_prepare,
495 ghid_block_hook_check,
496 ghid_block_hook_dispatch,
497 NULL // No destroy notification
500 static gboolean
501 ghid_block_hook_prepare (GSource *source,
502 gint *timeout)
504 hidval data = ((BlockHookSource *)source)->user_data;
505 ((BlockHookSource *)source)->func( data );
506 return FALSE;
509 static gboolean
510 ghid_block_hook_check (GSource *source)
512 return FALSE;
515 static gboolean
516 ghid_block_hook_dispatch (GSource *source,
517 GSourceFunc callback,
518 gpointer user_data)
520 return FALSE;
523 static hidval
524 ghid_add_block_hook (void (*func) (hidval data),
525 hidval user_data)
527 hidval ret;
528 BlockHookSource *source;
530 source = (BlockHookSource *)g_source_new (&ghid_block_hook_funcs, sizeof( BlockHookSource ));
532 source->func = func;
533 source->user_data = user_data;
535 g_source_attach ((GSource *)source, NULL);
537 ret.ptr = (void *) source;
538 return ret;
541 static void
542 ghid_stop_block_hook (hidval mlpoll)
544 GSource *source = (GSource *)mlpoll.ptr;
545 g_source_destroy( source );
549 ghid_confirm_dialog (char *msg, ...)
551 int rv = 0;
552 va_list ap;
553 char *cancelmsg = NULL, *okmsg = NULL;
554 static gint x = -1, y = -1;
555 GtkWidget *dialog;
556 GHidPort *out = &ghid_port;
558 va_start (ap, msg);
559 cancelmsg = va_arg (ap, char *);
560 okmsg = va_arg (ap, char *);
561 va_end (ap);
563 if (!cancelmsg)
565 cancelmsg = _("_Cancel");
566 okmsg = _("_OK");
569 dialog = gtk_message_dialog_new (GTK_WINDOW (out->top_window),
570 (GtkDialogFlags) (GTK_DIALOG_MODAL |
571 GTK_DIALOG_DESTROY_WITH_PARENT),
572 GTK_MESSAGE_QUESTION,
573 GTK_BUTTONS_NONE,
574 "%s", msg);
575 gtk_dialog_add_button (GTK_DIALOG (dialog),
576 cancelmsg, GTK_RESPONSE_CANCEL);
577 if (okmsg)
579 gtk_dialog_add_button (GTK_DIALOG (dialog),
580 okmsg, GTK_RESPONSE_OK);
583 if(x != -1) {
584 gtk_window_move(GTK_WINDOW (dialog), x, y);
587 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
588 rv = 1;
590 gtk_window_get_position(GTK_WINDOW (dialog), &x, &y);
592 gtk_widget_destroy (dialog);
593 return rv;
597 ghid_close_confirm_dialog ()
599 switch (ghid_dialog_close_confirm ())
601 case GUI_DIALOG_CLOSE_CONFIRM_SAVE:
603 if (hid_actionl ("Save", NULL))
604 { /* Save failed */
605 return 0; /* Cancel */
606 } else {
607 return 1; /* Close */
610 case GUI_DIALOG_CLOSE_CONFIRM_NOSAVE:
612 return 1; /* Close */
614 case GUI_DIALOG_CLOSE_CONFIRM_CANCEL:
615 default:
617 return 0; /* Cancel */
622 void
623 ghid_report_dialog (char *title, char *msg)
625 ghid_dialog_report (title, msg);
628 char *
629 ghid_prompt_for (const char *msg, const char *default_string)
631 char *rv;
633 rv = ghid_dialog_input (msg, default_string);
634 return rv;
637 /* FIXME -- implement a proper file select dialog */
638 #ifdef FIXME
639 char *
640 ghid_fileselect (const char *title, const char *descr,
641 char *default_file, char *default_ext,
642 const char *history_tag, int flags)
644 char *rv;
646 rv = ghid_dialog_input (title, default_file);
647 return rv;
649 #endif
651 void
652 ghid_show_item (void *item)
654 ghid_pinout_window_show (&ghid_port, (ElementType *) item);
657 void
658 ghid_beep ()
660 gdk_beep ();
663 struct progress_dialog
665 GtkWidget *dialog;
666 GtkWidget *message;
667 GtkWidget *progress;
668 gint response_id;
669 GMainLoop *loop;
670 gboolean destroyed;
671 gboolean started;
672 GTimer *timer;
674 gulong response_handler;
675 gulong destroy_handler;
676 gulong delete_handler;
679 static void
680 run_response_handler (GtkDialog *dialog,
681 gint response_id,
682 gpointer data)
684 struct progress_dialog *pd = data;
686 pd->response_id = response_id;
689 static gint
690 run_delete_handler (GtkDialog *dialog,
691 GdkEventAny *event,
692 gpointer data)
694 struct progress_dialog *pd = data;
696 pd->response_id = GTK_RESPONSE_DELETE_EVENT;
698 return TRUE; /* Do not destroy */
701 static void
702 run_destroy_handler (GtkDialog *dialog, gpointer data)
704 struct progress_dialog *pd = data;
706 pd->destroyed = TRUE;
709 static struct progress_dialog *
710 make_progress_dialog (void)
712 struct progress_dialog *pd;
713 GtkWidget *content_area;
714 GtkWidget *alignment;
715 GtkWidget *vbox;
717 pd = g_new0 (struct progress_dialog, 1);
718 pd->response_id = GTK_RESPONSE_NONE;
720 pd->dialog = gtk_dialog_new_with_buttons (_("Progress"),
721 GTK_WINDOW (gport->top_window),
722 /* Modal so nothing else can get events whilst
723 the main mainloop isn't running */
724 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
725 GTK_STOCK_CANCEL,
726 GTK_RESPONSE_CANCEL,
727 NULL);
729 gtk_window_set_deletable (GTK_WINDOW (pd->dialog), FALSE);
730 gtk_window_set_skip_pager_hint (GTK_WINDOW (pd->dialog), TRUE);
731 gtk_window_set_skip_taskbar_hint (GTK_WINDOW (pd->dialog), TRUE);
732 gtk_widget_set_size_request (pd->dialog, 300, -1);
734 pd->message = gtk_label_new (NULL);
735 gtk_misc_set_alignment (GTK_MISC (pd->message), 0., 0.);
737 pd->progress = gtk_progress_bar_new ();
738 gtk_widget_set_size_request (pd->progress, -1, 26);
740 vbox = gtk_vbox_new (false, 0);
741 gtk_box_pack_start (GTK_BOX (vbox), pd->message, true, true, 8);
742 gtk_box_pack_start (GTK_BOX (vbox), pd->progress, false, true, 8);
744 alignment = gtk_alignment_new (0., 0., 1., 1.);
745 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 8, 8, 8, 8);
746 gtk_container_add (GTK_CONTAINER (alignment), vbox);
748 content_area = gtk_dialog_get_content_area (GTK_DIALOG (pd->dialog));
749 gtk_box_pack_start (GTK_BOX (content_area), alignment, true, true, 0);
751 gtk_widget_show_all (alignment);
753 g_object_ref (pd->dialog);
754 gtk_window_present (GTK_WINDOW (pd->dialog));
756 pd->response_handler =
757 g_signal_connect (pd->dialog, "response",
758 G_CALLBACK (run_response_handler), pd);
759 pd->delete_handler =
760 g_signal_connect (pd->dialog, "delete-event",
761 G_CALLBACK (run_delete_handler), pd);
762 pd->destroy_handler =
763 g_signal_connect (pd->dialog, "destroy",
764 G_CALLBACK (run_destroy_handler), pd);
766 pd->loop = g_main_loop_new (NULL, FALSE);
767 pd->timer = g_timer_new ();
769 return pd;
772 static void
773 destroy_progress_dialog (struct progress_dialog *pd)
775 if (pd == NULL)
776 return;
778 if (!pd->destroyed)
780 g_signal_handler_disconnect (pd->dialog, pd->response_handler);
781 g_signal_handler_disconnect (pd->dialog, pd->delete_handler);
782 g_signal_handler_disconnect (pd->dialog, pd->destroy_handler);
785 g_timer_destroy (pd->timer);
786 g_object_unref (pd->dialog);
787 g_main_loop_unref (pd->loop);
789 gtk_widget_destroy (pd->dialog);
791 pd->loop = NULL;
792 g_free (pd);
795 static void
796 handle_progress_dialog_events (struct progress_dialog *pd)
798 GMainContext * context = g_main_loop_get_context (pd->loop);
800 /* Process events */
801 while (g_main_context_pending (context))
803 g_main_context_iteration (context, FALSE);
807 #define MIN_TIME_SEPARATION (50./1000.) /* 50ms */
808 static int
809 ghid_progress (int so_far, int total, const char *message)
811 static struct progress_dialog *pd = NULL;
813 /* If we are finished, destroy any dialog */
814 if (so_far == 0 && total == 0 && message == NULL)
816 destroy_progress_dialog (pd);
817 pd = NULL;
818 return 0;
821 if (pd == NULL)
822 pd = make_progress_dialog ();
824 /* We don't want to keep the underlying process too busy whilst we
825 * process events. If we get called quickly after the last progress
826 * update, wait a little bit before we respond - perhaps the next
827 * time progress is reported.
829 * The exception here is that we always want to process the first
830 * batch of events after having shown the dialog for the first time
832 if (pd->started && g_timer_elapsed (pd->timer, NULL) < MIN_TIME_SEPARATION)
833 return 0;
835 gtk_label_set_text (GTK_LABEL (pd->message), message);
836 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pd->progress),
837 (double)so_far / (double)total);
839 handle_progress_dialog_events (pd);
840 g_timer_start (pd->timer);
842 pd->started = TRUE;
844 return (pd->response_id == GTK_RESPONSE_CANCEL ||
845 pd->response_id == GTK_RESPONSE_DELETE_EVENT) ? 1 : 0;
848 /* ---------------------------------------------------------------------- */
851 typedef struct {
852 GtkWidget *del;
853 GtkWidget *w_name;
854 GtkWidget *w_value;
855 } AttrRow;
857 static AttrRow *attr_row = 0;
858 static int attr_num_rows = 0;
859 static int attr_max_rows = 0;
860 static AttributeListType *attributes_list;
861 static GtkWidget *attributes_dialog, *attr_table;
863 static void attributes_delete_callback (GtkWidget *w, void *v);
865 #define GA_RESPONSE_REVERT 1
866 #define GA_RESPONSE_NEW 2
868 static void
869 ghid_attr_set_table_size ()
871 gtk_table_resize (GTK_TABLE (attr_table), attr_num_rows > 0 ? attr_num_rows : 1, 3);
874 static void
875 ghid_attributes_need_rows (int new_max)
877 if (attr_max_rows < new_max)
879 if (attr_row)
880 attr_row = (AttrRow *) realloc (attr_row, new_max * sizeof(AttrRow));
881 else
882 attr_row = (AttrRow *) malloc (new_max * sizeof(AttrRow));
884 while (attr_max_rows < new_max)
886 /* add [attr_max_rows] */
887 attr_row[attr_max_rows].del = gtk_button_new_with_label ("del");
888 gtk_table_attach (GTK_TABLE (attr_table), attr_row[attr_max_rows].del,
889 0, 1,
890 attr_max_rows, attr_max_rows+1,
891 (GtkAttachOptions)(GTK_FILL | GTK_EXPAND),
892 GTK_FILL,
893 0, 0);
894 g_signal_connect (G_OBJECT (attr_row[attr_max_rows].del), "clicked",
895 G_CALLBACK (attributes_delete_callback), GINT_TO_POINTER (attr_max_rows) );
897 attr_row[attr_max_rows].w_name = gtk_entry_new ();
898 gtk_table_attach (GTK_TABLE (attr_table), attr_row[attr_max_rows].w_name,
899 1, 2,
900 attr_max_rows, attr_max_rows+1,
901 (GtkAttachOptions)(GTK_FILL | GTK_EXPAND),
902 GTK_FILL,
903 0, 0);
905 attr_row[attr_max_rows].w_value = gtk_entry_new ();
906 gtk_table_attach (GTK_TABLE (attr_table), attr_row[attr_max_rows].w_value,
907 2, 3,
908 attr_max_rows, attr_max_rows+1,
909 (GtkAttachOptions)(GTK_FILL | GTK_EXPAND),
910 GTK_FILL,
911 0, 0);
913 attr_max_rows ++;
916 /* Manage any previously unused rows we now need to show. */
917 while (attr_num_rows < new_max)
919 /* manage attr_num_rows */
920 gtk_widget_show (attr_row[attr_num_rows].del);
921 gtk_widget_show (attr_row[attr_num_rows].w_name);
922 gtk_widget_show (attr_row[attr_num_rows].w_value);
923 attr_num_rows ++;
927 static void
928 ghid_attributes_revert ()
930 int i;
932 ghid_attributes_need_rows (attributes_list->Number);
934 /* Unmanage any previously used rows we don't need. */
935 while (attr_num_rows > attributes_list->Number)
937 attr_num_rows --;
938 gtk_widget_hide (attr_row[attr_num_rows].del);
939 gtk_widget_hide (attr_row[attr_num_rows].w_name);
940 gtk_widget_hide (attr_row[attr_num_rows].w_value);
943 /* Fill in values */
944 for (i=0; i<attributes_list->Number; i++)
946 /* create row [i] */
947 gtk_entry_set_text (GTK_ENTRY (attr_row[i].w_name), attributes_list->List[i].name);
948 gtk_entry_set_text (GTK_ENTRY (attr_row[i].w_value), attributes_list->List[i].value);
949 #if 0
950 #endif
952 ghid_attr_set_table_size ();
955 static void
956 attributes_delete_callback (GtkWidget *w, void *v)
958 int i, n;
960 n = GPOINTER_TO_INT (v);
962 for (i=n; i<attr_num_rows-1; i++)
964 gtk_entry_set_text (GTK_ENTRY (attr_row[i].w_name),
965 gtk_entry_get_text (GTK_ENTRY (attr_row[i+1].w_name)));
966 gtk_entry_set_text (GTK_ENTRY (attr_row[i].w_value),
967 gtk_entry_get_text (GTK_ENTRY (attr_row[i+1].w_value)));
969 attr_num_rows --;
971 gtk_widget_hide (attr_row[attr_num_rows].del);
972 gtk_widget_hide (attr_row[attr_num_rows].w_name);
973 gtk_widget_hide (attr_row[attr_num_rows].w_value);
975 ghid_attr_set_table_size ();
978 static void
979 ghid_attributes (char *owner, AttributeListType *attrs)
981 GtkWidget *content_area;
982 int response;
984 attributes_list = attrs;
986 attr_max_rows = 0;
987 attr_num_rows = 0;
989 attributes_dialog = gtk_dialog_new_with_buttons (owner,
990 GTK_WINDOW (ghid_port.top_window),
991 GTK_DIALOG_MODAL,
992 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
993 "Revert", GA_RESPONSE_REVERT,
994 "New", GA_RESPONSE_NEW,
995 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
997 attr_table = gtk_table_new (attrs->Number, 3, 0);
999 content_area = gtk_dialog_get_content_area (GTK_DIALOG (attributes_dialog));
1000 gtk_box_pack_start (GTK_BOX (content_area), attr_table, FALSE, FALSE, 0);
1002 gtk_widget_show (attr_table);
1004 ghid_attributes_revert ();
1006 while (1)
1008 response = gtk_dialog_run (GTK_DIALOG (attributes_dialog));
1010 if (response == GTK_RESPONSE_CANCEL)
1011 break;
1013 if (response == GTK_RESPONSE_OK)
1015 int i;
1016 /* Copy the values back */
1017 for (i=0; i<attributes_list->Number; i++)
1019 if (attributes_list->List[i].name)
1020 free (attributes_list->List[i].name);
1021 if (attributes_list->List[i].value)
1022 free (attributes_list->List[i].value);
1024 if (attributes_list->Max < attr_num_rows)
1026 int sz = attr_num_rows * sizeof (AttributeType);
1027 if (attributes_list->List == NULL)
1028 attributes_list->List = (AttributeType *) malloc (sz);
1029 else
1030 attributes_list->List = (AttributeType *) realloc (attributes_list->List, sz);
1031 attributes_list->Max = attr_num_rows;
1033 for (i=0; i<attr_num_rows; i++)
1035 attributes_list->List[i].name = strdup (gtk_entry_get_text (GTK_ENTRY (attr_row[i].w_name)));
1036 attributes_list->List[i].value = strdup (gtk_entry_get_text (GTK_ENTRY (attr_row[i].w_value)));
1037 attributes_list->Number = attr_num_rows;
1040 break;
1043 if (response == GA_RESPONSE_REVERT)
1045 /* Revert */
1046 ghid_attributes_revert ();
1049 if (response == GA_RESPONSE_NEW)
1051 ghid_attributes_need_rows (attr_num_rows + 1); /* also bumps attr_num_rows */
1053 gtk_entry_set_text (GTK_ENTRY (attr_row[attr_num_rows-1].w_name), "");
1054 gtk_entry_set_text (GTK_ENTRY (attr_row[attr_num_rows-1].w_value), "");
1056 ghid_attr_set_table_size ();
1060 gtk_widget_destroy (attributes_dialog);
1061 free (attr_row);
1062 attr_row = NULL;
1065 /* ---------------------------------------------------------------------- */
1067 HID_DRC_GUI ghid_drc_gui = {
1068 1, /* log_drc_overview */
1069 0, /* log_drc_details */
1070 ghid_drc_window_reset_message,
1071 ghid_drc_window_append_violation,
1072 ghid_drc_window_throw_dialog,
1075 extern HID_Attribute *ghid_get_export_options (int *);
1078 /* ------------------------------------------------------------
1080 * Actions specific to the GTK HID follow from here
1085 /* ------------------------------------------------------------ */
1086 static const char about_syntax[] =
1087 "About()";
1089 static const char about_help[] =
1090 N_("Tell the user about this version of PCB.");
1092 /* %start-doc actions About
1094 This just pops up a dialog telling the user which version of
1095 @code{pcb} they're running.
1097 %end-doc */
1100 static int
1101 About (int argc, char **argv, Coord x, Coord y)
1103 ghid_dialog_about ();
1104 return 0;
1107 /* ------------------------------------------------------------ */
1108 static const char getxy_syntax[] =
1109 "GetXY()";
1111 static const char getxy_help[] =
1112 N_("Get a coordinate.");
1114 /* %start-doc actions GetXY
1116 Prompts the user for a coordinate, if one is not already selected.
1118 %end-doc */
1120 static int
1121 GetXY (int argc, char **argv, Coord x, Coord y)
1123 return 0;
1126 /* ---------------------------------------------------------------------- */
1128 static int PointCursor (int argc, char **argv, Coord x, Coord y)
1130 if (!ghidgui)
1131 return 0;
1133 if (argc > 0)
1134 ghid_point_cursor ();
1135 else
1136 ghid_mode_cursor (Settings.Mode);
1137 return 0;
1140 /* ---------------------------------------------------------------------- */
1142 static int
1143 RouteStylesChanged (int argc, char **argv, Coord x, Coord y)
1145 if (!ghidgui || !ghidgui->route_style_selector)
1146 return 0;
1148 ghid_route_style_selector_sync
1149 (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector),
1150 Settings.LineThickness, Settings.ViaDrillingHole,
1151 Settings.ViaThickness, Settings.Keepaway);
1153 return 0;
1156 /* ---------------------------------------------------------------------- */
1159 PCBChanged (int argc, char **argv, Coord x, Coord y)
1161 if (!ghidgui)
1162 return 0;
1164 ghid_window_set_name_label (PCB->Name);
1166 if (!gport->pixmap)
1167 return 0;
1169 if (ghidgui->route_style_selector)
1171 ghid_route_style_selector_empty
1172 (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
1173 make_route_style_buttons
1174 (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
1176 RouteStylesChanged (0, NULL, 0, 0);
1178 ghid_port_ranges_scale ();
1179 ghid_zoom_view_fit ();
1180 ghid_sync_with_new_layout ();
1181 return 0;
1184 /* ---------------------------------------------------------------------- */
1186 static int
1187 LayerGroupsChanged (int argc, char **argv, Coord x, Coord y)
1189 printf (_("LayerGroupsChanged -- not implemented\n"));
1190 return 0;
1193 /* ---------------------------------------------------------------------- */
1195 static int
1196 LibraryChanged (int argc, char **argv, Coord x, Coord y)
1198 /* No need to show the library window every time it changes...
1199 * ghid_library_window_show (&ghid_port, FALSE);
1201 return 0;
1204 /* ---------------------------------------------------------------------- */
1206 static int
1207 Command (int argc, char **argv, Coord x, Coord y)
1209 ghid_handle_user_command (TRUE);
1210 return 0;
1213 /* ---------------------------------------------------------------------- */
1215 static int
1216 Load (int argc, char **argv, Coord x, Coord y)
1218 char *function;
1219 char *name = NULL;
1221 static gchar *current_element_dir = NULL;
1222 static gchar *current_layout_dir = NULL;
1223 static gchar *current_netlist_dir = NULL;
1225 /* we've been given the file name */
1226 if (argc > 1)
1227 return hid_actionv ("LoadFrom", argc, argv);
1229 function = argc ? argv[0] : (char *)"Layout";
1231 if (strcasecmp (function, "Netlist") == 0)
1233 name = ghid_dialog_file_select_open (_("Load netlist file"),
1234 &current_netlist_dir,
1235 Settings.FilePath);
1237 else if (strcasecmp (function, "ElementToBuffer") == 0)
1239 name = ghid_dialog_file_select_open (_("Load element to buffer"),
1240 &current_element_dir,
1241 Settings.LibraryTree);
1243 else if (strcasecmp (function, "LayoutToBuffer") == 0)
1245 name = ghid_dialog_file_select_open (_("Load layout file to buffer"),
1246 &current_layout_dir,
1247 Settings.FilePath);
1249 else if (strcasecmp (function, "Layout") == 0)
1251 name = ghid_dialog_file_select_open (_("Load layout file"),
1252 &current_layout_dir,
1253 Settings.FilePath);
1256 if (name)
1258 if (Settings.verbose)
1259 fprintf (stderr, "%s: Calling LoadFrom(%s, %s)\n", __FUNCTION__,
1260 function, name);
1261 hid_actionl ("LoadFrom", function, name, NULL);
1262 g_free (name);
1265 return 0;
1269 /* ---------------------------------------------------------------------- */
1270 static const char save_syntax[] =
1271 "Save()\n"
1272 "Save(Layout|LayoutAs)\n"
1273 "Save(AllConnections|AllUnusedPins|ElementConnections)\n"
1274 "Save(PasteBuffer)";
1276 static const char save_help[] =
1277 N_("Save layout and/or element data to a user-selected file.");
1279 /* %start-doc actions Save
1281 This action is a GUI front-end to the core's @code{SaveTo} action
1282 (@pxref{SaveTo Action}). If you happen to pass a filename, like
1283 @code{SaveTo}, then @code{SaveTo} is called directly. Else, the
1284 user is prompted for a filename to save, and then @code{SaveTo} is
1285 called with that filename.
1287 %end-doc */
1289 static int
1290 Save (int argc, char **argv, Coord x, Coord y)
1292 char *function;
1293 char *name;
1294 char *prompt;
1296 static gchar *current_dir = NULL;
1298 if (argc > 1)
1299 return hid_actionv ("SaveTo", argc, argv);
1301 function = argc ? argv[0] : (char *)"Layout";
1303 if (strcasecmp (function, "Layout") == 0)
1304 if (PCB->Filename)
1305 return hid_actionl ("SaveTo", "Layout", PCB->Filename, NULL);
1307 if (strcasecmp (function, "PasteBuffer") == 0)
1308 prompt = _("Save element as");
1309 else
1310 prompt = _("Save layout as");
1312 name = ghid_dialog_file_select_save (prompt,
1313 &current_dir,
1314 PCB->Filename, Settings.FilePath);
1316 if (name)
1318 if (Settings.verbose)
1319 fprintf (stderr, "%s: Calling SaveTo(%s, %s)\n",
1320 __FUNCTION__, function, name);
1322 if (strcasecmp (function, "PasteBuffer") == 0)
1323 hid_actionl ("PasteBuffer", "Save", name, NULL);
1324 else
1327 * if we got this far and the function is Layout, then
1328 * we really needed it to be a LayoutAs. Otherwise
1329 * ActionSaveTo() will ignore the new file name we
1330 * just obtained.
1332 if (strcasecmp (function, "Layout") == 0)
1333 hid_actionl ("SaveTo", "LayoutAs", name, NULL);
1334 else
1335 hid_actionl ("SaveTo", function, name, NULL);
1337 g_free (name);
1339 else
1341 return 1;
1344 return 0;
1347 /* ---------------------------------------------------------------------- */
1348 static const char swapsides_syntax[] =
1349 "SwapSides(|v|h|r)";
1351 static const char swapsides_help[] =
1352 N_("Swaps the side of the board you're looking at.");
1354 /* %start-doc actions SwapSides
1356 This action changes the way you view the board.
1358 @table @code
1360 @item v
1361 Flips the board over vertically (up/down).
1363 @item h
1364 Flips the board over horizontally (left/right), like flipping pages in
1365 a book.
1367 @item r
1368 Rotates the board 180 degrees without changing sides.
1370 @end table
1372 If no argument is given, the board isn't moved but the opposite side
1373 is shown.
1375 Normally, this action changes which pads and silk layer are drawn as
1376 true silk, and which are drawn as the "invisible" layer. It also
1377 determines which solder mask you see.
1379 As a special case, if the layer group for the side you're looking at
1380 is visible and currently active, and the layer group for the opposite
1381 is not visible (i.e. disabled), then this action will also swap which
1382 layer group is visible and active, effectively swapping the ``working
1383 side'' of the board.
1385 %end-doc */
1388 static int
1389 SwapSides (int argc, char **argv, Coord x, Coord y)
1391 int active_group = GetLayerGroupNumberByNumber (LayerStack[0]);
1392 int comp_group = GetLayerGroupNumberByNumber (component_silk_layer);
1393 int solder_group = GetLayerGroupNumberByNumber (solder_silk_layer);
1394 bool comp_on = LAYER_PTR (PCB->LayerGroups.Entries[comp_group][0])->On;
1395 bool solder_on = LAYER_PTR (PCB->LayerGroups.Entries[solder_group][0])->On;
1397 if (argc > 0)
1399 switch (argv[0][0]) {
1400 case 'h':
1401 case 'H':
1402 ghid_flip_view (gport->pcb_x, gport->pcb_y, true, false);
1403 break;
1404 case 'v':
1405 case 'V':
1406 ghid_flip_view (gport->pcb_x, gport->pcb_y, false, true);
1407 break;
1408 case 'r':
1409 case 'R':
1410 ghid_flip_view (gport->pcb_x, gport->pcb_y, true, true);
1411 Settings.ShowSolderSide = !Settings.ShowSolderSide; /* Swapped back below */
1412 break;
1413 default:
1414 return 1;
1418 Settings.ShowSolderSide = !Settings.ShowSolderSide;
1420 if ((active_group == comp_group && comp_on && !solder_on) ||
1421 (active_group == solder_group && solder_on && !comp_on))
1423 bool new_solder_vis = Settings.ShowSolderSide;
1425 ChangeGroupVisibility (PCB->LayerGroups.Entries[comp_group][0],
1426 !new_solder_vis, !new_solder_vis);
1427 ChangeGroupVisibility (PCB->LayerGroups.Entries[solder_group][0],
1428 new_solder_vis, new_solder_vis);
1431 return 0;
1434 /* ------------------------------------------------------------ */
1436 static const char print_syntax[] =
1437 "Print()";
1439 static const char print_help[] =
1440 N_("Print the layout.");
1442 /* %start-doc actions Print
1444 This will find the default printing HID, prompt the user for its
1445 options, and print the layout.
1447 %end-doc */
1449 static int
1450 Print (int argc, char **argv, Coord x, Coord y)
1452 HID **hids;
1453 int i;
1454 HID *printer = NULL;
1456 hids = hid_enumerate ();
1457 for (i = 0; hids[i]; i++)
1459 if (hids[i]->printer)
1460 printer = hids[i];
1463 if (printer == NULL)
1465 gui->log (_("Can't find a suitable printer HID"));
1466 return -1;
1469 /* check if layout is empty */
1470 if (!IsDataEmpty (PCB->Data))
1472 ghid_dialog_print (printer);
1474 else
1475 gui->log (_("Can't print empty layout"));
1477 return 0;
1481 /* ------------------------------------------------------------ */
1483 static HID_Attribute
1484 printer_calibrate_attrs[] = {
1485 {N_("Enter Values here:"), "",
1486 HID_Label, 0, 0, {0, 0, 0}, 0, 0},
1487 {N_("x-calibration"), N_("X scale for calibrating your printer"),
1488 HID_Real, 0.5, 25, {0, 0, 1.00}, 0, 0},
1489 {N_("y-calibration"), N_("Y scale for calibrating your printer"),
1490 HID_Real, 0.5, 25, {0, 0, 1.00}, 0, 0}
1492 static HID_Attr_Val printer_calibrate_values[3];
1494 static const char printcalibrate_syntax[] =
1495 "PrintCalibrate()";
1497 static const char printcalibrate_help[] =
1498 N_("Calibrate the printer.");
1500 /* %start-doc actions PrintCalibrate
1502 This will print a calibration page, which you would measure and type
1503 the measurements in, so that future printouts will be more precise.
1505 %end-doc */
1507 static int
1508 PrintCalibrate (int argc, char **argv, Coord x, Coord y)
1510 HID *printer = hid_find_printer ();
1511 printer->calibrate (0.0, 0.0);
1513 if (gui->attribute_dialog (printer_calibrate_attrs, 3,
1514 printer_calibrate_values,
1515 _("Printer Calibration Values"),
1516 _("Enter calibration values for your printer")))
1517 return 1;
1518 printer->calibrate (printer_calibrate_values[1].real_value,
1519 printer_calibrate_values[2].real_value);
1520 return 0;
1523 /* ------------------------------------------------------------ */
1525 static int
1526 Export (int argc, char **argv, Coord x, Coord y)
1529 /* check if layout is empty */
1530 if (!IsDataEmpty (PCB->Data))
1532 ghid_dialog_export ();
1534 else
1535 gui->log (_("Can't export empty layout"));
1537 return 0;
1540 /* ------------------------------------------------------------ */
1542 static int
1543 Benchmark (int argc, char **argv, Coord x, Coord y)
1545 int i = 0;
1546 time_t start, end;
1547 GdkDisplay *display;
1549 display = gdk_drawable_get_display (gport->drawable);
1551 gdk_display_sync (display);
1552 time (&start);
1555 ghid_invalidate_all ();
1556 gdk_window_process_updates (gtk_widget_get_window (gport->drawing_area),
1557 FALSE);
1558 time (&end);
1559 i++;
1561 while (end - start < 10);
1563 printf (_("%g redraws per second\n"), i / 10.0);
1565 return 0;
1568 /* ------------------------------------------------------------ */
1570 static const char center_syntax[] =
1571 "Center()\n";
1573 static const char center_help[] =
1574 N_("Moves the pointer to the center of the window.");
1576 /* %start-doc actions Center
1578 Move the pointer to the center of the window, but only if it's
1579 currently within the window already.
1581 %end-doc */
1583 static int
1584 Center(int argc, char **argv, Coord pcb_x, Coord pcb_y)
1586 GdkDisplay *display;
1587 GdkScreen *screen;
1588 int offset_x, offset_y;
1589 int widget_x, widget_y;
1590 int pointer_x, pointer_y;
1592 if (argc != 0)
1593 AFAIL (center);
1595 /* Aim to put the given x, y PCB coordinates in the center of the widget */
1596 widget_x = gport->width / 2;
1597 widget_y = gport->height / 2;
1599 ghid_pan_view_abs (pcb_x, pcb_y, widget_x, widget_y);
1601 /* Now move the mouse pointer to the place where the board location
1602 * actually ended up.
1604 * XXX: Should only do this if we confirm we are inside our window?
1607 ghid_pcb_to_event_coords (pcb_x, pcb_y, &widget_x, &widget_y);
1608 gdk_window_get_origin (gtk_widget_get_window (gport->drawing_area),
1609 &offset_x, &offset_y);
1611 pointer_x = offset_x + widget_x;
1612 pointer_y = offset_y + widget_y;
1614 display = gdk_display_get_default ();
1615 screen = gdk_display_get_default_screen (display);
1616 gdk_display_warp_pointer (display, screen, pointer_x, pointer_y);
1618 return 0;
1621 /* ------------------------------------------------------------ */
1622 static const char cursor_syntax[] =
1623 "Cursor(Type,DeltaUp,DeltaRight,Units)";
1625 static const char cursor_help[] =
1626 N_("Move the cursor.");
1628 /* %start-doc actions Cursor
1630 This action moves the mouse cursor. Unlike other actions which take
1631 coordinates, this action's coordinates are always relative to the
1632 user's view of the board. Thus, a positive @var{DeltaUp} may move the
1633 cursor towards the board origin if the board is inverted.
1635 Type is one of @samp{Pan} or @samp{Warp}. @samp{Pan} causes the
1636 viewport to move such that the crosshair is under the mouse cursor.
1637 @samp{Warp} causes the mouse cursor to move to be above the crosshair.
1639 @var{Units} can be one of the following:
1641 @table @samp
1643 @item mil
1644 @itemx mm
1645 The cursor is moved by that amount, in board units.
1647 @item grid
1648 The cursor is moved by that many grid points.
1650 @item view
1651 The values are percentages of the viewport's view. Thus, a pan of
1652 @samp{100} would scroll the viewport by exactly the width of the
1653 current view.
1655 @item board
1656 The values are percentages of the board size. Thus, a move of
1657 @samp{50,50} moves you halfway across the board.
1659 @end table
1661 %end-doc */
1663 static int
1664 CursorAction(int argc, char **argv, Coord x, Coord y)
1666 UnitList extra_units_x = {
1667 { "grid", PCB->Grid, 0 },
1668 { "view", gport->view.width, UNIT_PERCENT },
1669 { "board", PCB->MaxWidth, UNIT_PERCENT },
1670 { "", 0, 0 }
1672 UnitList extra_units_y = {
1673 { "grid", PCB->Grid, 0 },
1674 { "view", gport->view.height, UNIT_PERCENT },
1675 { "board", PCB->MaxHeight, UNIT_PERCENT },
1676 { "", 0, 0 }
1678 int pan_warp = HID_SC_DO_NOTHING;
1679 double dx, dy;
1681 if (argc != 4)
1682 AFAIL (cursor);
1684 if (strcasecmp (argv[0], "pan") == 0)
1685 pan_warp = HID_SC_PAN_VIEWPORT;
1686 else if (strcasecmp (argv[0], "warp") == 0)
1687 pan_warp = HID_SC_WARP_POINTER;
1688 else
1689 AFAIL (cursor);
1691 dx = GetValueEx (argv[1], argv[3], NULL, extra_units_x, "");
1692 if (gport->view.flip_x)
1693 dx = -dx;
1694 dy = GetValueEx (argv[2], argv[3], NULL, extra_units_y, "");
1695 if (!gport->view.flip_y)
1696 dy = -dy;
1698 EventMoveCrosshair (Crosshair.X + dx, Crosshair.Y + dy);
1699 gui->set_crosshair (Crosshair.X, Crosshair.Y, pan_warp);
1701 return 0;
1703 /* ------------------------------------------------------------ */
1705 static const char dowindows_syntax[] =
1706 "DoWindows(1|2|3|4|5|6)\n"
1707 "DoWindows(Layout|Library|Log|Netlist|Preferences|DRC)";
1709 static const char dowindows_help[] =
1710 N_("Open various GUI windows.");
1712 /* %start-doc actions DoWindows
1714 @table @code
1716 @item 1
1717 @itemx Layout
1718 Open the layout window. Since the layout window is always shown
1719 anyway, this has no effect.
1721 @item 2
1722 @itemx Library
1723 Open the library window.
1725 @item 3
1726 @itemx Log
1727 Open the log window.
1729 @item 4
1730 @itemx Netlist
1731 Open the netlist window.
1733 @item 5
1734 @itemx Preferences
1735 Open the preferences window.
1737 @item 6
1738 @itemx DRC
1739 Open the DRC violations window.
1741 @end table
1743 %end-doc */
1745 static int
1746 DoWindows (int argc, char **argv, Coord x, Coord y)
1748 char *a = argc == 1 ? argv[0] : (char *)"";
1750 if (strcmp (a, "1") == 0 || strcasecmp (a, "Layout") == 0)
1753 else if (strcmp (a, "2") == 0 || strcasecmp (a, "Library") == 0)
1755 ghid_library_window_show (gport, TRUE);
1757 else if (strcmp (a, "3") == 0 || strcasecmp (a, "Log") == 0)
1759 ghid_log_window_show (TRUE);
1761 else if (strcmp (a, "4") == 0 || strcasecmp (a, "Netlist") == 0)
1763 ghid_netlist_window_show (gport, TRUE);
1765 else if (strcmp (a, "5") == 0 || strcasecmp (a, "Preferences") == 0)
1767 ghid_config_window_show ();
1769 else if (strcmp (a, "6") == 0 || strcasecmp (a, "DRC") == 0)
1771 ghid_drc_window_show (TRUE);
1773 else
1775 AFAIL (dowindows);
1778 return 0;
1781 /* ------------------------------------------------------------ */
1782 static const char setunits_syntax[] =
1783 "SetUnits(mm|mil)";
1785 static const char setunits_help[] =
1786 N_("Set the default measurement units.");
1788 /* %start-doc actions SetUnits
1790 @table @code
1792 @item mil
1793 Sets the display units to mils (1/1000 inch).
1795 @item mm
1796 Sets the display units to millimeters.
1798 @end table
1800 %end-doc */
1802 static int
1803 SetUnits (int argc, char **argv, Coord x, Coord y)
1805 const Unit *new_unit;
1806 if (argc == 0)
1807 return 0;
1809 new_unit = get_unit_struct (argv[0]);
1810 if (new_unit != NULL && new_unit->allow != NO_PRINT)
1812 Settings.grid_unit = new_unit;
1813 Settings.increments = get_increments_struct (Settings.grid_unit->family);
1814 AttributePut (PCB, "PCB::grid::unit", argv[0]);
1817 ghid_config_handle_units_changed ();
1819 ghid_set_status_line_label ();
1821 /* FIXME ?
1822 * lesstif_sizes_reset ();
1823 * lesstif_styles_update_values ();
1825 return 0;
1828 /* ------------------------------------------------------------ */
1829 static const char scroll_syntax[] =
1830 "Scroll(up|down|left|right, [div])";
1832 static const char scroll_help[] =
1833 N_("Scroll the viewport.");
1835 /* % start-doc actions Scroll
1837 @item up|down|left|right
1838 Specifies the direction to scroll
1840 @item div
1841 Optional. Specifies how much to scroll by. The viewport is scrolled
1842 by 1/div of what is visible, so div = 1 scrolls a whole page. If not
1843 default is given, div=40.
1845 %end-doc */
1847 static int
1848 ScrollAction (int argc, char **argv, Coord x, Coord y)
1850 gdouble dx = 0.0, dy = 0.0;
1851 int div = 40;
1853 if (!ghidgui)
1854 return 0;
1856 if (argc != 1 && argc != 2)
1857 AFAIL (scroll);
1859 if (argc == 2)
1860 div = atoi(argv[1]);
1862 if (strcasecmp (argv[0], "up") == 0)
1863 dy = -gport->view.height / div;
1864 else if (strcasecmp (argv[0], "down") == 0)
1865 dy = gport->view.height / div;
1866 else if (strcasecmp (argv[0], "right") == 0)
1867 dx = gport->view.width / div;
1868 else if (strcasecmp (argv[0], "left") == 0)
1869 dx = -gport->view.width / div;
1870 else
1871 AFAIL (scroll);
1873 ghid_pan_view_rel (dx, dy);
1875 return 0;
1878 /* ------------------------------------------------------------ */
1879 static const char pan_syntax[] =
1880 "Pan([thumb], Mode)";
1882 static const char pan_help[] =
1883 N_("Start or stop panning (Mode = 1 to start, 0 to stop)\n"
1884 "Optional thumb argument is ignored for now in gtk hid.\n");
1886 /* %start-doc actions Pan
1888 Start or stop panning. To start call with Mode = 1, to stop call with
1889 Mode = 0.
1891 %end-doc */
1893 static int
1894 PanAction (int argc, char **argv, Coord x, Coord y)
1896 int mode;
1898 if (!ghidgui)
1899 return 0;
1901 if (argc != 1 && argc != 2)
1902 AFAIL (pan);
1904 if (argc == 1)
1905 mode = atoi(argv[0]);
1906 else
1908 mode = atoi(argv[1]);
1909 Message (_("The gtk gui currently ignores the optional first argument "
1910 "to the Pan action.\nFeel free to provide patches.\n"));
1913 gport->panning = mode;
1915 return 0;
1918 /* ------------------------------------------------------------ */
1919 static const char popup_syntax[] =
1920 "Popup(MenuName, [Button])";
1922 static const char popup_help[] =
1923 N_("Bring up the popup menu specified by @code{MenuName}.\n"
1924 "If called by a mouse event then the mouse button number\n"
1925 "must be specified as the optional second argument.");
1927 /* %start-doc actions Popup
1929 This just pops up the specified menu. The menu must have been defined
1930 as a named subresource of the Popups resource in the menu resource
1931 file. The second, optional (and ignored) argument represents the mouse
1932 button number which is triggering the popup.
1934 %end-doc */
1937 static int
1938 Popup (int argc, char **argv, Coord x, Coord y)
1940 GtkMenu *menu;
1942 if (argc != 1 && argc != 2)
1943 AFAIL (popup);
1945 menu = ghid_main_menu_get_popup (GHID_MAIN_MENU (ghidgui->menu_bar), argv[0]);
1946 if (! GTK_IS_MENU (menu))
1948 Message (_("The specified popup menu \"%s\" has not been defined.\n"), argv[0]);
1949 return 1;
1951 else
1953 ghidgui->in_popup = TRUE;
1954 gtk_widget_grab_focus (ghid_port.drawing_area);
1955 gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0,
1956 gtk_get_current_event_time());
1958 return 0;
1960 /* ------------------------------------------------------------ */
1961 static const char importgui_syntax[] =
1962 "ImportGUI()";
1964 static const char importgui_help[] =
1965 N_("Asks user which schematics to import into PCB.\n");
1967 /* %start-doc actions ImportGUI
1969 Asks user which schematics to import into PCB.
1971 %end-doc */
1974 static int
1975 ImportGUI (int argc, char **argv, Coord x, Coord y)
1977 GSList *names = NULL;
1978 gchar *name = NULL;
1979 gchar sname[128];
1980 static gchar *current_layout_dir = NULL;
1981 static int I_am_recursing = 0;
1982 int rv, nsources;
1984 if (I_am_recursing)
1985 return 1;
1988 names = ghid_dialog_file_select_multiple (_("Load schematics"),
1989 &current_layout_dir,
1990 Settings.FilePath);
1992 nsources = 0;
1993 while (names != NULL)
1995 name = names->data;
1997 #ifdef DEBUG
1998 printf("File selected = %s\n", name);
1999 #endif
2001 sprintf (sname, "import::src%d", nsources);
2002 AttributePut (PCB, sname, name);
2004 g_free (name);
2005 nsources++;
2006 names = g_slist_next (names);
2008 g_slist_free (names);
2010 I_am_recursing = 1;
2011 rv = hid_action ("Import");
2012 I_am_recursing = 0;
2014 return rv;
2017 /* ------------------------------------------------------------ */
2018 static int
2019 Busy (int argc, char **argv, Coord x, Coord y)
2021 ghid_watch_cursor ();
2022 return 0;
2025 HID_Action ghid_main_action_list[] = {
2026 {"About", 0, About, about_help, about_syntax},
2027 {"Benchmark", 0, Benchmark},
2028 {"Busy", 0, Busy},
2029 {"Center", N_("Click on a location to center"), Center, center_help, center_syntax},
2030 {"Command", 0, Command},
2031 {"Cursor", 0, CursorAction, cursor_help, cursor_syntax},
2032 {"DoWindows", 0, DoWindows, dowindows_help, dowindows_syntax},
2033 {"Export", 0, Export},
2034 {"GetXY", "", GetXY, getxy_help, getxy_syntax},
2035 {"ImportGUI", 0, ImportGUI, importgui_help, importgui_syntax},
2036 {"LayerGroupsChanged", 0, LayerGroupsChanged},
2037 {"LibraryChanged", 0, LibraryChanged},
2038 {"Load", 0, Load},
2039 {"Pan", 0, PanAction, pan_help, pan_syntax},
2040 {"PCBChanged", 0, PCBChanged},
2041 {"PointCursor", 0, PointCursor},
2042 {"Popup", 0, Popup, popup_help, popup_syntax},
2043 {"Print", 0, Print,
2044 print_help, print_syntax},
2045 {"PrintCalibrate", 0, PrintCalibrate,
2046 printcalibrate_help, printcalibrate_syntax},
2047 {"RouteStylesChanged", 0, RouteStylesChanged},
2048 {"Save", 0, Save, save_help, save_syntax},
2049 {"Scroll", N_("Click on a place to scroll"), ScrollAction, scroll_help, scroll_syntax},
2050 {"SetUnits", 0, SetUnits, setunits_help, setunits_syntax},
2051 {"SwapSides", 0, SwapSides, swapsides_help, swapsides_syntax},
2052 {"Zoom", N_("Click on zoom focus"), Zoom, zoom_help, zoom_syntax}
2055 REGISTER_ACTIONS (ghid_main_action_list)
2058 static int
2059 flag_flipx (void *data)
2061 return gport->view.flip_x;
2064 static int
2065 flag_flipy (void *data)
2067 return gport->view.flip_y;
2070 HID_Flag ghid_main_flag_list[] = {
2071 {"flip_x", flag_flipx, NULL},
2072 {"flip_y", flag_flipy, NULL}
2075 REGISTER_FLAGS (ghid_main_flag_list)
2077 #include "dolists.h"
2080 * We will need these for finding the windows installation
2081 * directory. Without that we can't find our fonts and
2082 * footprint libraries.
2084 #ifdef WIN32
2085 #include <windows.h>
2086 #include <winreg.h>
2087 #endif
2089 HID ghid_hid;
2091 void
2092 hid_gtk_init ()
2094 #ifdef WIN32
2095 char * tmps;
2096 char * share_dir;
2097 char *loader_cache;
2098 FILE *loader_file;
2099 #endif
2101 #ifdef WIN32
2102 tmps = g_win32_get_package_installation_directory (PACKAGE "-" VERSION, NULL);
2103 #define REST_OF_PATH G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S PACKAGE
2104 #define REST_OF_CACHE G_DIR_SEPARATOR_S "loaders.cache"
2105 share_dir = (char *) malloc(strlen(tmps) +
2106 strlen(REST_OF_PATH) +
2108 sprintf (share_dir, "%s%s", tmps, REST_OF_PATH);
2110 /* Point to our gdk-pixbuf loader cache. */
2111 loader_cache = (char *) malloc (strlen (bindir) +
2112 strlen (REST_OF_CACHE) +
2114 sprintf (loader_cache, "%s%s", bindir, REST_OF_CACHE);
2115 loader_file = fopen (loader_cache, "r");
2116 if (loader_file)
2118 fclose (loader_file);
2119 g_setenv ("GDK_PIXBUF_MODULE_FILE", loader_cache, TRUE);
2122 free (tmps);
2123 #undef REST_OF_PATH
2124 printf ("\"Share\" installation path is \"%s\"\n", share_dir);
2125 free (share_dir);
2126 #endif
2128 memset (&ghid_hid, 0, sizeof (HID));
2130 common_nogui_init (&ghid_hid);
2131 common_draw_helpers_init (&ghid_hid);
2133 ghid_hid.struct_size = sizeof (HID);
2134 ghid_hid.name = "gtk";
2135 ghid_hid.description = "Gtk - The Gimp Toolkit";
2136 ghid_hid.gui = 1;
2137 ghid_hid.poly_after = 1;
2139 ghid_hid.get_export_options = ghid_get_export_options;
2140 ghid_hid.do_export = ghid_do_export;
2141 ghid_hid.parse_arguments = ghid_parse_arguments;
2142 ghid_hid.invalidate_lr = ghid_invalidate_lr;
2143 ghid_hid.invalidate_all = ghid_invalidate_all;
2144 ghid_hid.notify_crosshair_change = ghid_notify_crosshair_change;
2145 ghid_hid.notify_mark_change = ghid_notify_mark_change;
2146 ghid_hid.set_layer = ghid_set_layer;
2147 ghid_hid.make_gc = ghid_make_gc;
2148 ghid_hid.destroy_gc = ghid_destroy_gc;
2149 ghid_hid.use_mask = ghid_use_mask;
2150 ghid_hid.set_color = ghid_set_color;
2151 ghid_hid.set_line_cap = ghid_set_line_cap;
2152 ghid_hid.set_line_width = ghid_set_line_width;
2153 ghid_hid.set_draw_xor = ghid_set_draw_xor;
2154 ghid_hid.draw_line = ghid_draw_line;
2155 ghid_hid.draw_arc = ghid_draw_arc;
2156 ghid_hid.draw_rect = ghid_draw_rect;
2157 ghid_hid.fill_circle = ghid_fill_circle;
2158 ghid_hid.fill_polygon = ghid_fill_polygon;
2159 ghid_hid.fill_rect = ghid_fill_rect;
2161 ghid_hid.calibrate = ghid_calibrate;
2162 ghid_hid.shift_is_pressed = ghid_shift_is_pressed;
2163 ghid_hid.control_is_pressed = ghid_control_is_pressed;
2164 ghid_hid.mod1_is_pressed = ghid_mod1_is_pressed,
2165 ghid_hid.get_coords = ghid_get_coords;
2166 ghid_hid.set_crosshair = ghid_set_crosshair;
2167 ghid_hid.add_timer = ghid_add_timer;
2168 ghid_hid.stop_timer = ghid_stop_timer;
2169 ghid_hid.watch_file = ghid_watch_file;
2170 ghid_hid.unwatch_file = ghid_unwatch_file;
2171 ghid_hid.add_block_hook = ghid_add_block_hook;
2172 ghid_hid.stop_block_hook = ghid_stop_block_hook;
2174 ghid_hid.log = ghid_log;
2175 ghid_hid.logv = ghid_logv;
2176 ghid_hid.confirm_dialog = ghid_confirm_dialog;
2177 ghid_hid.close_confirm_dialog = ghid_close_confirm_dialog;
2178 ghid_hid.report_dialog = ghid_report_dialog;
2179 ghid_hid.prompt_for = ghid_prompt_for;
2180 ghid_hid.fileselect = ghid_fileselect;
2181 ghid_hid.attribute_dialog = ghid_attribute_dialog;
2182 ghid_hid.show_item = ghid_show_item;
2183 ghid_hid.beep = ghid_beep;
2184 ghid_hid.progress = ghid_progress;
2185 ghid_hid.drc_gui = &ghid_drc_gui,
2186 ghid_hid.edit_attributes = ghid_attributes;
2188 ghid_hid.request_debug_draw = ghid_request_debug_draw;
2189 ghid_hid.flush_debug_draw = ghid_flush_debug_draw;
2190 ghid_hid.finish_debug_draw = ghid_finish_debug_draw;
2192 ghid_hid.notify_save_pcb = ghid_notify_save_pcb;
2193 ghid_hid.notify_filename_changed = ghid_notify_filename_changed;
2195 hid_register_hid (&ghid_hid);
2196 #include "gtk_lists.h"