Re-ordered all references in the style selector dialog to have one consistent ordering.
[geda-pcb/whiteaudio.git] / src / hid / gtk / gtkhid-main.c
blob1957be6f6ea6032a231521934ce60319423d0e43
1 /* $Id$ */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdio.h>
8 #include <stdlib.h>
9 #ifdef HAVE_STRING_H
10 #include <string.h>
11 #endif
12 #include <math.h>
13 #include <time.h>
16 #include "action.h"
17 #include "crosshair.h"
18 #include "error.h"
19 #include "../hidint.h"
20 #include "gui.h"
21 #include "hid/common/hidnogui.h"
22 #include "hid/common/draw_helpers.h"
23 #include "pcb-printf.h"
25 #ifdef HAVE_LIBDMALLOC
26 #include <dmalloc.h>
27 #endif
30 RCSID ("$Id$");
33 static void
34 pan_common (GHidPort *port)
36 int event_x, event_y;
38 /* We need to fix up the PCB coordinates corresponding to the last
39 * event so convert it back to event coordinates temporarily. */
40 ghid_pcb_to_event_coords (gport->pcb_x, gport->pcb_y, &event_x, &event_y);
42 /* Don't pan so far the board is completely off the screen */
43 port->view.x0 = MAX (-port->view.width, port->view.x0);
44 port->view.y0 = MAX (-port->view.height, port->view.y0);
45 port->view.x0 = MIN ( port->view.x0, PCB->MaxWidth);
46 port->view.y0 = MIN ( port->view.y0, PCB->MaxHeight);
48 /* Fix up noted event coordinates to match where we clamped. Alternatively
49 * we could call ghid_note_event_location (NULL); to get a new pointer
50 * location, but this costs us an xserver round-trip (on X11 platforms)
52 ghid_event_to_pcb_coords (event_x, event_y, &gport->pcb_x, &gport->pcb_y);
54 ghidgui->adjustment_changed_holdoff = TRUE;
55 gtk_range_set_value (GTK_RANGE (ghidgui->h_range), gport->view.x0);
56 gtk_range_set_value (GTK_RANGE (ghidgui->v_range), gport->view.y0);
57 ghidgui->adjustment_changed_holdoff = FALSE;
59 ghid_port_ranges_changed();
62 static void
63 ghid_pan_view_abs (Coord pcb_x, Coord pcb_y, int widget_x, int widget_y)
65 gport->view.x0 = SIDE_X (pcb_x) - widget_x * gport->view.coord_per_px;
66 gport->view.y0 = SIDE_Y (pcb_y) - widget_y * gport->view.coord_per_px;
68 pan_common (gport);
71 void
72 ghid_pan_view_rel (Coord dx, Coord dy)
74 gport->view.x0 += dx;
75 gport->view.y0 += dy;
77 pan_common (gport);
81 /* gport->view.coord_per_px:
82 * zoom value is PCB units per screen pixel. Larger numbers mean zooming
83 * out - the largest value means you are looking at the whole board.
85 * gport->view_width and gport->view_height are in PCB coordinates
88 #define ALLOW_ZOOM_OUT_BY 10 /* Arbitrary, and same as the lesstif HID */
89 static void
90 ghid_zoom_view_abs (Coord center_x, Coord center_y, double new_zoom)
92 double min_zoom, max_zoom;
93 double xtmp, ytmp;
95 /* Limit the "minimum" zoom constant (maximum zoom), at 1 pixel per PCB
96 * unit, and set the "maximum" zoom constant (minimum zoom), such that
97 * the entire board just fits inside the viewport
99 min_zoom = 1;
100 max_zoom = MAX (PCB->MaxWidth / gport->width,
101 PCB->MaxHeight / gport->height) * ALLOW_ZOOM_OUT_BY;
102 new_zoom = MIN (MAX (min_zoom, new_zoom), max_zoom);
104 if (gport->view.coord_per_px == new_zoom)
105 return;
107 xtmp = (SIDE_X (center_x) - gport->view.x0) / (double)gport->view.width;
108 ytmp = (SIDE_Y (center_y) - gport->view.y0) / (double)gport->view.height;
110 gport->view.coord_per_px = new_zoom;
111 pixel_slop = new_zoom;
112 ghid_port_ranges_scale ();
114 gport->view.x0 = SIDE_X (center_x) - xtmp * gport->view.width;
115 gport->view.y0 = SIDE_Y (center_y) - ytmp * gport->view.height;
117 pan_common (gport);
119 ghid_set_status_line_label ();
122 static void
123 ghid_zoom_view_rel (Coord center_x, Coord center_y, double factor)
125 ghid_zoom_view_abs (center_x, center_y, gport->view.coord_per_px * factor);
128 static void
129 ghid_zoom_view_fit (void)
131 ghid_pan_view_abs (0, 0, 0, 0);
132 ghid_zoom_view_abs (0, 0, MAX (PCB->MaxWidth / gport->width,
133 PCB->MaxHeight / gport->height));
136 static void
137 ghid_flip_view (Coord center_x, Coord center_y, bool flip_x, bool flip_y)
139 int widget_x, widget_y;
141 /* Work out where on the screen the flip point is */
142 ghid_pcb_to_event_coords (center_x, center_y, &widget_x, &widget_y);
144 gport->view.flip_x = gport->view.flip_x != flip_x;
145 gport->view.flip_y = gport->view.flip_y != flip_y;
147 /* Pan the board so the center location remains in the same place */
148 ghid_pan_view_abs (center_x, center_y, widget_x, widget_y);
150 ghid_invalidate_all ();
153 /* ------------------------------------------------------------ */
155 static const char zoom_syntax[] =
156 "Zoom()\n"
157 "Zoom(factor)";
160 static const char zoom_help[] =
161 N_("Various zoom factor changes.");
163 /* %start-doc actions Zoom
164 Changes the zoom (magnification) of the view of the board. If no
165 arguments are passed, the view is scaled such that the board just fits
166 inside the visible window (i.e. ``view all''). Otherwise,
167 @var{factor} specifies a change in zoom factor. It may be prefixed by
168 @code{+}, @code{-}, or @code{=} to change how the zoom factor is
169 modified. The @var{factor} is a floating point number, such as
170 @code{1.5} or @code{0.75}.
172 @table @code
174 @item +@var{factor}
175 Values greater than 1.0 cause the board to be drawn smaller; more of
176 the board will be visible. Values between 0.0 and 1.0 cause the board
177 to be drawn bigger; less of the board will be visible.
179 @item -@var{factor}
180 Values greater than 1.0 cause the board to be drawn bigger; less of
181 the board will be visible. Values between 0.0 and 1.0 cause the board
182 to be drawn smaller; more of the board will be visible.
184 @item =@var{factor}
186 The @var{factor} is an absolute zoom factor; the unit for this value
187 is "PCB units per screen pixel". Since PCB units are 0.01 mil, a
188 @var{factor} of 1000 means 10 mils (0.01 in) per pixel, or 100 DPI,
189 about the actual resolution of most screens - resulting in an "actual
190 size" board. Similarly, a @var{factor} of 100 gives you a 10x actual
191 size.
193 @end table
195 Note that zoom factors of zero are silently ignored.
199 %end-doc */
201 static int
202 Zoom (int argc, char **argv, Coord x, Coord y)
204 const char *vp;
205 double v;
207 if (argc > 1)
208 AFAIL (zoom);
210 if (argc < 1)
212 ghid_zoom_view_fit ();
213 return 0;
216 vp = argv[0];
217 if (*vp == '+' || *vp == '-' || *vp == '=')
218 vp++;
219 v = strtod (vp, 0);
220 if (v <= 0)
221 return 1;
222 switch (argv[0][0])
224 case '-':
225 ghid_zoom_view_rel (x, y, 1 / v);
226 break;
227 default:
228 case '+':
229 ghid_zoom_view_rel (x, y, v);
230 break;
231 case '=':
232 ghid_zoom_view_abs (x, y, v);
233 break;
236 return 0;
239 /* ------------------------------------------------------------ */
241 void
242 ghid_calibrate (double xval, double yval)
244 printf (_("ghid_calibrate() -- not implemented\n"));
247 static int ghid_gui_is_up = 0;
249 void
250 ghid_notify_gui_is_up ()
252 ghid_gui_is_up = 1;
256 ghid_shift_is_pressed ()
258 GdkModifierType mask;
259 GHidPort *out = &ghid_port;
261 if( ! ghid_gui_is_up )
262 return 0;
264 gdk_window_get_pointer (gtk_widget_get_window (out->drawing_area),
265 NULL, NULL, &mask);
266 return (mask & GDK_SHIFT_MASK) ? TRUE : FALSE;
270 ghid_control_is_pressed ()
272 GdkModifierType mask;
273 GHidPort *out = &ghid_port;
275 if( ! ghid_gui_is_up )
276 return 0;
278 gdk_window_get_pointer (gtk_widget_get_window (out->drawing_area),
279 NULL, NULL, &mask);
280 return (mask & GDK_CONTROL_MASK) ? TRUE : FALSE;
284 ghid_mod1_is_pressed ()
286 GdkModifierType mask;
287 GHidPort *out = &ghid_port;
289 if( ! ghid_gui_is_up )
290 return 0;
292 gdk_window_get_pointer (gtk_widget_get_window (out->drawing_area),
293 NULL, NULL, &mask);
294 #ifdef __APPLE__
295 return (mask & ( 1 << 13 ) ) ? TRUE : FALSE; // The option key is not MOD1, although it should be...
296 #else
297 return (mask & GDK_MOD1_MASK) ? TRUE : FALSE;
298 #endif
301 void
302 ghid_set_crosshair (int x, int y, int action)
304 GdkDisplay *display;
305 GdkScreen *screen;
306 int offset_x, offset_y;
307 int widget_x, widget_y;
308 int pointer_x, pointer_y;
309 Coord pcb_x, pcb_y;
311 if (gport->crosshair_x != x || gport->crosshair_y != y)
313 ghid_set_cursor_position_labels ();
314 gport->crosshair_x = x;
315 gport->crosshair_y = y;
317 /* FIXME - does this trigger the idle_proc stuff? It is in the
318 * lesstif HID. Maybe something is needed here?
320 * need_idle_proc ();
324 if (action != HID_SC_PAN_VIEWPORT &&
325 action != HID_SC_WARP_POINTER)
326 return;
328 /* Find out where the drawing area is on the screen. gdk_display_get_pointer
329 * and gdk_display_warp_pointer work relative to the whole display, whilst
330 * our coordinates are relative to the drawing area origin.
332 gdk_window_get_origin (gtk_widget_get_window (gport->drawing_area),
333 &offset_x, &offset_y);
334 display = gdk_display_get_default ();
336 switch (action) {
337 case HID_SC_PAN_VIEWPORT:
338 /* Pan the board in the viewport so that the crosshair (who's location
339 * relative on the board was set above) lands where the pointer is.
340 * We pass the request to pan a particular point on the board to a
341 * given widget coordinate of the viewport into the rendering code
344 /* Find out where the pointer is relative to the display */
345 gdk_display_get_pointer (display, NULL, &pointer_x, &pointer_y, NULL);
347 widget_x = pointer_x - offset_x;
348 widget_y = pointer_y - offset_y;
350 ghid_event_to_pcb_coords (widget_x, widget_y, &pcb_x, &pcb_y);
351 ghid_pan_view_abs (pcb_x, pcb_y, widget_x, widget_y);
353 /* Just in case we couldn't pan the board the whole way,
354 * we warp the pointer to where the crosshair DID land.
356 /* Fall through */
358 case HID_SC_WARP_POINTER:
359 screen = gdk_display_get_default_screen (display);
361 ghid_pcb_to_event_coords (x, y, &widget_x, &widget_y);
363 pointer_x = offset_x + widget_x;
364 pointer_y = offset_y + widget_y;
366 gdk_display_warp_pointer (display, screen, pointer_x, pointer_y);
368 break;
372 typedef struct
374 void (*func) (hidval);
375 guint id;
376 hidval user_data;
378 GuiTimer;
380 /* We need a wrapper around the hid timer because a gtk timer needs
381 | to return FALSE else the timer will be restarted.
383 static gboolean
384 ghid_timer (GuiTimer * timer)
386 (*timer->func) (timer->user_data);
387 ghid_mode_cursor (Settings.Mode);
388 return FALSE; /* Turns timer off */
391 hidval
392 ghid_add_timer (void (*func) (hidval user_data),
393 unsigned long milliseconds, hidval user_data)
395 GuiTimer *timer = g_new0 (GuiTimer, 1);
396 hidval ret;
398 timer->func = func;
399 timer->user_data = user_data;
400 timer->id = g_timeout_add (milliseconds, (GSourceFunc) ghid_timer, timer);
401 ret.ptr = (void *) timer;
402 return ret;
405 void
406 ghid_stop_timer (hidval timer)
408 void *ptr = timer.ptr;
410 g_source_remove (((GuiTimer *) ptr)->id);
411 g_free( ptr );
414 typedef struct
416 void (*func) ( hidval, int, unsigned int, hidval );
417 hidval user_data;
418 int fd;
419 GIOChannel *channel;
420 gint id;
422 GuiWatch;
424 /* We need a wrapper around the hid file watch to pass the correct flags
426 static gboolean
427 ghid_watch (GIOChannel *source, GIOCondition condition, gpointer data)
429 unsigned int pcb_condition = 0;
430 hidval x;
431 GuiWatch *watch = (GuiWatch*)data;
433 if (condition & G_IO_IN)
434 pcb_condition |= PCB_WATCH_READABLE;
435 if (condition & G_IO_OUT)
436 pcb_condition |= PCB_WATCH_WRITABLE;
437 if (condition & G_IO_ERR)
438 pcb_condition |= PCB_WATCH_ERROR;
439 if (condition & G_IO_HUP)
440 pcb_condition |= PCB_WATCH_HANGUP;
442 x.ptr = (void *) watch;
443 watch->func (x, watch->fd, pcb_condition, watch->user_data);
444 ghid_mode_cursor (Settings.Mode);
446 return TRUE; /* Leave watch on */
449 hidval
450 ghid_watch_file (int fd, unsigned int condition, void (*func) (hidval watch, int fd, unsigned int condition, hidval user_data),
451 hidval user_data)
453 GuiWatch *watch = g_new0 (GuiWatch, 1);
454 hidval ret;
455 unsigned int glib_condition = 0;
457 if (condition & PCB_WATCH_READABLE)
458 glib_condition |= G_IO_IN;
459 if (condition & PCB_WATCH_WRITABLE)
460 glib_condition |= G_IO_OUT;
461 if (condition & PCB_WATCH_ERROR)
462 glib_condition |= G_IO_ERR;
463 if (condition & PCB_WATCH_HANGUP)
464 glib_condition |= G_IO_HUP;
466 watch->func = func;
467 watch->user_data = user_data;
468 watch->fd = fd;
469 watch->channel = g_io_channel_unix_new( fd );
470 watch->id = g_io_add_watch( watch->channel, (GIOCondition)glib_condition, ghid_watch, watch );
472 ret.ptr = (void *) watch;
473 return ret;
476 void
477 ghid_unwatch_file (hidval data)
479 GuiWatch *watch = (GuiWatch*)data.ptr;
481 g_io_channel_shutdown( watch->channel, TRUE, NULL );
482 g_io_channel_unref( watch->channel );
483 g_free( watch );
486 typedef struct
488 GSource source;
489 void (*func) (hidval user_data);
490 hidval user_data;
491 } BlockHookSource;
493 static gboolean ghid_block_hook_prepare (GSource *source,
494 gint *timeout);
495 static gboolean ghid_block_hook_check (GSource *source);
496 static gboolean ghid_block_hook_dispatch (GSource *source,
497 GSourceFunc callback,
498 gpointer user_data);
500 static GSourceFuncs ghid_block_hook_funcs = {
501 ghid_block_hook_prepare,
502 ghid_block_hook_check,
503 ghid_block_hook_dispatch,
504 NULL // No destroy notification
507 static gboolean
508 ghid_block_hook_prepare (GSource *source,
509 gint *timeout)
511 hidval data = ((BlockHookSource *)source)->user_data;
512 ((BlockHookSource *)source)->func( data );
513 return FALSE;
516 static gboolean
517 ghid_block_hook_check (GSource *source)
519 return FALSE;
522 static gboolean
523 ghid_block_hook_dispatch (GSource *source,
524 GSourceFunc callback,
525 gpointer user_data)
527 return FALSE;
530 static hidval
531 ghid_add_block_hook (void (*func) (hidval data),
532 hidval user_data)
534 hidval ret;
535 BlockHookSource *source;
537 source = (BlockHookSource *)g_source_new (&ghid_block_hook_funcs, sizeof( BlockHookSource ));
539 source->func = func;
540 source->user_data = user_data;
542 g_source_attach ((GSource *)source, NULL);
544 ret.ptr = (void *) source;
545 return ret;
548 static void
549 ghid_stop_block_hook (hidval mlpoll)
551 GSource *source = (GSource *)mlpoll.ptr;
552 g_source_destroy( source );
556 ghid_confirm_dialog (char *msg, ...)
558 int rv = 0;
559 va_list ap;
560 char *cancelmsg = NULL, *okmsg = NULL;
561 static gint x = -1, y = -1;
562 GtkWidget *dialog;
563 GHidPort *out = &ghid_port;
565 va_start (ap, msg);
566 cancelmsg = va_arg (ap, char *);
567 okmsg = va_arg (ap, char *);
568 va_end (ap);
570 if (!cancelmsg)
572 cancelmsg = _("_Cancel");
573 okmsg = _("_OK");
576 dialog = gtk_message_dialog_new (GTK_WINDOW (out->top_window),
577 (GtkDialogFlags) (GTK_DIALOG_MODAL |
578 GTK_DIALOG_DESTROY_WITH_PARENT),
579 GTK_MESSAGE_QUESTION,
580 GTK_BUTTONS_NONE,
581 "%s", msg);
582 gtk_dialog_add_button (GTK_DIALOG (dialog),
583 cancelmsg, GTK_RESPONSE_CANCEL);
584 if (okmsg)
586 gtk_dialog_add_button (GTK_DIALOG (dialog),
587 okmsg, GTK_RESPONSE_OK);
590 if(x != -1) {
591 gtk_window_move(GTK_WINDOW (dialog), x, y);
594 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
595 rv = 1;
597 gtk_window_get_position(GTK_WINDOW (dialog), &x, &y);
599 gtk_widget_destroy (dialog);
600 return rv;
604 ghid_close_confirm_dialog ()
606 switch (ghid_dialog_close_confirm ())
608 case GUI_DIALOG_CLOSE_CONFIRM_SAVE:
610 if (hid_actionl ("Save", NULL))
611 { /* Save failed */
612 return 0; /* Cancel */
613 } else {
614 return 1; /* Close */
617 case GUI_DIALOG_CLOSE_CONFIRM_NOSAVE:
619 return 1; /* Close */
621 case GUI_DIALOG_CLOSE_CONFIRM_CANCEL:
622 default:
624 return 0; /* Cancel */
629 void
630 ghid_report_dialog (char *title, char *msg)
632 ghid_dialog_report (title, msg);
635 char *
636 ghid_prompt_for (const char *msg, const char *default_string)
638 char *rv;
640 rv = ghid_dialog_input (msg, default_string);
641 return rv;
644 /* FIXME -- implement a proper file select dialog */
645 #ifdef FIXME
646 char *
647 ghid_fileselect (const char *title, const char *descr,
648 char *default_file, char *default_ext,
649 const char *history_tag, int flags)
651 char *rv;
653 rv = ghid_dialog_input (title, default_file);
654 return rv;
656 #endif
658 void
659 ghid_show_item (void *item)
661 ghid_pinout_window_show (&ghid_port, (ElementTypePtr) item);
664 void
665 ghid_beep ()
667 gdk_beep ();
670 struct progress_dialog
672 GtkWidget *dialog;
673 GtkWidget *message;
674 GtkWidget *progress;
675 gint response_id;
676 GMainLoop *loop;
677 gboolean destroyed;
678 gboolean started;
679 GTimer *timer;
681 gulong response_handler;
682 gulong destroy_handler;
683 gulong delete_handler;
686 static void
687 run_response_handler (GtkDialog *dialog,
688 gint response_id,
689 gpointer data)
691 struct progress_dialog *pd = data;
693 pd->response_id = response_id;
696 static gint
697 run_delete_handler (GtkDialog *dialog,
698 GdkEventAny *event,
699 gpointer data)
701 struct progress_dialog *pd = data;
703 pd->response_id = GTK_RESPONSE_DELETE_EVENT;
705 return TRUE; /* Do not destroy */
708 static void
709 run_destroy_handler (GtkDialog *dialog, gpointer data)
711 struct progress_dialog *pd = data;
713 pd->destroyed = TRUE;
716 static struct progress_dialog *
717 make_progress_dialog (void)
719 struct progress_dialog *pd;
720 GtkWidget *content_area;
721 GtkWidget *alignment;
722 GtkWidget *vbox;
724 pd = g_new0 (struct progress_dialog, 1);
725 pd->response_id = GTK_RESPONSE_NONE;
727 pd->dialog = gtk_dialog_new_with_buttons (_("Progress"),
728 GTK_WINDOW (gport->top_window),
729 /* Modal so nothing else can get events whilst
730 the main mainloop isn't running */
731 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
732 GTK_STOCK_CANCEL,
733 GTK_RESPONSE_CANCEL,
734 NULL);
736 gtk_window_set_deletable (GTK_WINDOW (pd->dialog), FALSE);
737 gtk_window_set_skip_pager_hint (GTK_WINDOW (pd->dialog), TRUE);
738 gtk_window_set_skip_taskbar_hint (GTK_WINDOW (pd->dialog), TRUE);
739 gtk_widget_set_size_request (pd->dialog, 300, -1);
741 pd->message = gtk_label_new (NULL);
742 gtk_misc_set_alignment (GTK_MISC (pd->message), 0., 0.);
744 pd->progress = gtk_progress_bar_new ();
745 gtk_widget_set_size_request (pd->progress, -1, 26);
747 vbox = gtk_vbox_new (false, 0);
748 gtk_box_pack_start (GTK_BOX (vbox), pd->message, true, true, 8);
749 gtk_box_pack_start (GTK_BOX (vbox), pd->progress, false, true, 8);
751 alignment = gtk_alignment_new (0., 0., 1., 1.);
752 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 8, 8, 8, 8);
753 gtk_container_add (GTK_CONTAINER (alignment), vbox);
755 content_area = gtk_dialog_get_content_area (GTK_DIALOG (pd->dialog));
756 gtk_box_pack_start (GTK_BOX (content_area), alignment, true, true, 0);
758 gtk_widget_show_all (alignment);
760 g_object_ref (pd->dialog);
761 gtk_window_present (GTK_WINDOW (pd->dialog));
763 pd->response_handler =
764 g_signal_connect (pd->dialog, "response",
765 G_CALLBACK (run_response_handler), pd);
766 pd->delete_handler =
767 g_signal_connect (pd->dialog, "delete-event",
768 G_CALLBACK (run_delete_handler), pd);
769 pd->destroy_handler =
770 g_signal_connect (pd->dialog, "destroy",
771 G_CALLBACK (run_destroy_handler), pd);
773 pd->loop = g_main_loop_new (NULL, FALSE);
774 pd->timer = g_timer_new ();
776 return pd;
779 static void
780 destroy_progress_dialog (struct progress_dialog *pd)
782 if (pd == NULL)
783 return;
785 if (!pd->destroyed)
787 g_signal_handler_disconnect (pd->dialog, pd->response_handler);
788 g_signal_handler_disconnect (pd->dialog, pd->delete_handler);
789 g_signal_handler_disconnect (pd->dialog, pd->destroy_handler);
792 g_timer_destroy (pd->timer);
793 g_object_unref (pd->dialog);
794 g_main_loop_unref (pd->loop);
796 gtk_widget_destroy (pd->dialog);
798 pd->loop = NULL;
799 g_free (pd);
802 static void
803 handle_progress_dialog_events (struct progress_dialog *pd)
805 GMainContext * context = g_main_loop_get_context (pd->loop);
807 /* Process events */
808 while (g_main_context_pending (context))
810 g_main_context_iteration (context, FALSE);
814 #define MIN_TIME_SEPARATION (50./1000.) /* 50ms */
815 static int
816 ghid_progress (int so_far, int total, const char *message)
818 static struct progress_dialog *pd = NULL;
820 /* If we are finished, destroy any dialog */
821 if (so_far == 0 && total == 0 && message == NULL)
823 destroy_progress_dialog (pd);
824 pd = NULL;
825 return 0;
828 if (pd == NULL)
829 pd = make_progress_dialog ();
831 /* We don't want to keep the underlying process too busy whilst we
832 * process events. If we get called quickly after the last progress
833 * update, wait a little bit before we respond - perhaps the next
834 * time progress is reported.
836 * The exception here is that we always want to process the first
837 * batch of events after having shown the dialog for the first time
839 if (pd->started && g_timer_elapsed (pd->timer, NULL) < MIN_TIME_SEPARATION)
840 return 0;
842 gtk_label_set_text (GTK_LABEL (pd->message), message);
843 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pd->progress),
844 (double)so_far / (double)total);
846 handle_progress_dialog_events (pd);
847 g_timer_start (pd->timer);
849 pd->started = TRUE;
851 return (pd->response_id == GTK_RESPONSE_CANCEL ||
852 pd->response_id == GTK_RESPONSE_DELETE_EVENT) ? 1 : 0;
855 /* ---------------------------------------------------------------------- */
858 typedef struct {
859 GtkWidget *del;
860 GtkWidget *w_name;
861 GtkWidget *w_value;
862 } AttrRow;
864 static AttrRow *attr_row = 0;
865 static int attr_num_rows = 0;
866 static int attr_max_rows = 0;
867 static AttributeListType *attributes_list;
868 static GtkWidget *attributes_dialog, *attr_table;
870 static void attributes_delete_callback (GtkWidget *w, void *v);
872 #define GA_RESPONSE_REVERT 1
873 #define GA_RESPONSE_NEW 2
875 static void
876 ghid_attr_set_table_size ()
878 gtk_table_resize (GTK_TABLE (attr_table), attr_num_rows > 0 ? attr_num_rows : 1, 3);
881 static void
882 ghid_attributes_need_rows (int new_max)
884 if (attr_max_rows < new_max)
886 if (attr_row)
887 attr_row = (AttrRow *) realloc (attr_row, new_max * sizeof(AttrRow));
888 else
889 attr_row = (AttrRow *) malloc (new_max * sizeof(AttrRow));
891 while (attr_max_rows < new_max)
893 /* add [attr_max_rows] */
894 attr_row[attr_max_rows].del = gtk_button_new_with_label ("del");
895 gtk_table_attach (GTK_TABLE (attr_table), attr_row[attr_max_rows].del,
896 0, 1,
897 attr_max_rows, attr_max_rows+1,
898 (GtkAttachOptions)(GTK_FILL | GTK_EXPAND),
899 GTK_FILL,
900 0, 0);
901 g_signal_connect (G_OBJECT (attr_row[attr_max_rows].del), "clicked",
902 G_CALLBACK (attributes_delete_callback), GINT_TO_POINTER (attr_max_rows) );
904 attr_row[attr_max_rows].w_name = gtk_entry_new ();
905 gtk_table_attach (GTK_TABLE (attr_table), attr_row[attr_max_rows].w_name,
906 1, 2,
907 attr_max_rows, attr_max_rows+1,
908 (GtkAttachOptions)(GTK_FILL | GTK_EXPAND),
909 GTK_FILL,
910 0, 0);
912 attr_row[attr_max_rows].w_value = gtk_entry_new ();
913 gtk_table_attach (GTK_TABLE (attr_table), attr_row[attr_max_rows].w_value,
914 2, 3,
915 attr_max_rows, attr_max_rows+1,
916 (GtkAttachOptions)(GTK_FILL | GTK_EXPAND),
917 GTK_FILL,
918 0, 0);
920 attr_max_rows ++;
923 /* Manage any previously unused rows we now need to show. */
924 while (attr_num_rows < new_max)
926 /* manage attr_num_rows */
927 gtk_widget_show (attr_row[attr_num_rows].del);
928 gtk_widget_show (attr_row[attr_num_rows].w_name);
929 gtk_widget_show (attr_row[attr_num_rows].w_value);
930 attr_num_rows ++;
934 static void
935 ghid_attributes_revert ()
937 int i;
939 ghid_attributes_need_rows (attributes_list->Number);
941 /* Unmanage any previously used rows we don't need. */
942 while (attr_num_rows > attributes_list->Number)
944 attr_num_rows --;
945 gtk_widget_hide (attr_row[attr_num_rows].del);
946 gtk_widget_hide (attr_row[attr_num_rows].w_name);
947 gtk_widget_hide (attr_row[attr_num_rows].w_value);
950 /* Fill in values */
951 for (i=0; i<attributes_list->Number; i++)
953 /* create row [i] */
954 gtk_entry_set_text (GTK_ENTRY (attr_row[i].w_name), attributes_list->List[i].name);
955 gtk_entry_set_text (GTK_ENTRY (attr_row[i].w_value), attributes_list->List[i].value);
956 #if 0
957 #endif
959 ghid_attr_set_table_size ();
962 static void
963 attributes_delete_callback (GtkWidget *w, void *v)
965 int i, n;
967 n = GPOINTER_TO_INT (v);
969 for (i=n; i<attr_num_rows-1; i++)
971 gtk_entry_set_text (GTK_ENTRY (attr_row[i].w_name),
972 gtk_entry_get_text (GTK_ENTRY (attr_row[i+1].w_name)));
973 gtk_entry_set_text (GTK_ENTRY (attr_row[i].w_value),
974 gtk_entry_get_text (GTK_ENTRY (attr_row[i+1].w_value)));
976 attr_num_rows --;
978 gtk_widget_hide (attr_row[attr_num_rows].del);
979 gtk_widget_hide (attr_row[attr_num_rows].w_name);
980 gtk_widget_hide (attr_row[attr_num_rows].w_value);
982 ghid_attr_set_table_size ();
985 static void
986 ghid_attributes (char *owner, AttributeListType *attrs)
988 GtkWidget *content_area;
989 int response;
991 attributes_list = attrs;
993 attr_max_rows = 0;
994 attr_num_rows = 0;
996 attributes_dialog = gtk_dialog_new_with_buttons (owner,
997 GTK_WINDOW (ghid_port.top_window),
998 GTK_DIALOG_MODAL,
999 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1000 "Revert", GA_RESPONSE_REVERT,
1001 "New", GA_RESPONSE_NEW,
1002 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1004 attr_table = gtk_table_new (attrs->Number, 3, 0);
1006 content_area = gtk_dialog_get_content_area (GTK_DIALOG (attributes_dialog));
1007 gtk_box_pack_start (GTK_BOX (content_area), attr_table, FALSE, FALSE, 0);
1009 gtk_widget_show (attr_table);
1011 ghid_attributes_revert ();
1013 while (1)
1015 response = gtk_dialog_run (GTK_DIALOG (attributes_dialog));
1017 if (response == GTK_RESPONSE_CANCEL)
1018 break;
1020 if (response == GTK_RESPONSE_OK)
1022 int i;
1023 /* Copy the values back */
1024 for (i=0; i<attributes_list->Number; i++)
1026 if (attributes_list->List[i].name)
1027 free (attributes_list->List[i].name);
1028 if (attributes_list->List[i].value)
1029 free (attributes_list->List[i].value);
1031 if (attributes_list->Max < attr_num_rows)
1033 int sz = attr_num_rows * sizeof (AttributeType);
1034 if (attributes_list->List == NULL)
1035 attributes_list->List = (AttributeType *) malloc (sz);
1036 else
1037 attributes_list->List = (AttributeType *) realloc (attributes_list->List, sz);
1038 attributes_list->Max = attr_num_rows;
1040 for (i=0; i<attr_num_rows; i++)
1042 attributes_list->List[i].name = strdup (gtk_entry_get_text (GTK_ENTRY (attr_row[i].w_name)));
1043 attributes_list->List[i].value = strdup (gtk_entry_get_text (GTK_ENTRY (attr_row[i].w_value)));
1044 attributes_list->Number = attr_num_rows;
1047 break;
1050 if (response == GA_RESPONSE_REVERT)
1052 /* Revert */
1053 ghid_attributes_revert ();
1056 if (response == GA_RESPONSE_NEW)
1058 ghid_attributes_need_rows (attr_num_rows + 1); /* also bumps attr_num_rows */
1060 gtk_entry_set_text (GTK_ENTRY (attr_row[attr_num_rows-1].w_name), "");
1061 gtk_entry_set_text (GTK_ENTRY (attr_row[attr_num_rows-1].w_value), "");
1063 ghid_attr_set_table_size ();
1067 gtk_widget_destroy (attributes_dialog);
1068 free (attr_row);
1069 attr_row = NULL;
1072 /* ---------------------------------------------------------------------- */
1074 HID_DRC_GUI ghid_drc_gui = {
1075 1, /* log_drc_overview */
1076 0, /* log_drc_details */
1077 ghid_drc_window_reset_message,
1078 ghid_drc_window_append_violation,
1079 ghid_drc_window_throw_dialog,
1082 extern HID_Attribute *ghid_get_export_options (int *);
1085 /* ------------------------------------------------------------
1087 * Actions specific to the GTK HID follow from here
1092 /* ------------------------------------------------------------ */
1093 static const char about_syntax[] =
1094 "About()";
1096 static const char about_help[] =
1097 N_("Tell the user about this version of PCB.");
1099 /* %start-doc actions About
1101 This just pops up a dialog telling the user which version of
1102 @code{pcb} they're running.
1104 %end-doc */
1107 static int
1108 About (int argc, char **argv, Coord x, Coord y)
1110 ghid_dialog_about ();
1111 return 0;
1114 /* ------------------------------------------------------------ */
1115 static const char getxy_syntax[] =
1116 "GetXY()";
1118 static const char getxy_help[] =
1119 N_("Get a coordinate.");
1121 /* %start-doc actions GetXY
1123 Prompts the user for a coordinate, if one is not already selected.
1125 %end-doc */
1127 static int
1128 GetXY (int argc, char **argv, Coord x, Coord y)
1130 return 0;
1133 /* ---------------------------------------------------------------------- */
1135 static int PointCursor (int argc, char **argv, Coord x, Coord y)
1137 if (!ghidgui)
1138 return 0;
1140 if (argc > 0)
1141 ghid_point_cursor ();
1142 else
1143 ghid_mode_cursor (Settings.Mode);
1144 return 0;
1147 /* ---------------------------------------------------------------------- */
1149 static int
1150 RouteStylesChanged (int argc, char **argv, Coord x, Coord y)
1152 if (!ghidgui || !ghidgui->route_style_selector)
1153 return 0;
1155 ghid_route_style_selector_sync
1156 (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector),
1157 Settings.LineThickness, Settings.ViaDrillingHole,
1158 Settings.ViaThickness, Settings.Keepaway);
1160 return 0;
1163 /* ---------------------------------------------------------------------- */
1166 PCBChanged (int argc, char **argv, Coord x, Coord y)
1168 if (!ghidgui)
1169 return 0;
1171 ghid_window_set_name_label (PCB->Name);
1173 if (!gport->pixmap)
1174 return 0;
1176 if (ghidgui->route_style_selector)
1178 ghid_route_style_selector_empty
1179 (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
1180 make_route_style_buttons
1181 (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
1183 RouteStylesChanged (0, NULL, 0, 0);
1185 ghid_port_ranges_scale ();
1186 ghid_zoom_view_fit ();
1187 ghid_sync_with_new_layout ();
1188 return 0;
1191 /* ---------------------------------------------------------------------- */
1193 static int
1194 LayerGroupsChanged (int argc, char **argv, Coord x, Coord y)
1196 printf (_("LayerGroupsChanged -- not implemented\n"));
1197 return 0;
1200 /* ---------------------------------------------------------------------- */
1202 static int
1203 LibraryChanged (int argc, char **argv, Coord x, Coord y)
1205 /* No need to show the library window every time it changes...
1206 * ghid_library_window_show (&ghid_port, FALSE);
1208 return 0;
1211 /* ---------------------------------------------------------------------- */
1213 static int
1214 Command (int argc, char **argv, Coord x, Coord y)
1216 ghid_handle_user_command (TRUE);
1217 return 0;
1220 /* ---------------------------------------------------------------------- */
1222 static int
1223 Load (int argc, char **argv, Coord x, Coord y)
1225 char *function;
1226 char *name = NULL;
1228 static gchar *current_element_dir = NULL;
1229 static gchar *current_layout_dir = NULL;
1230 static gchar *current_netlist_dir = NULL;
1232 /* we've been given the file name */
1233 if (argc > 1)
1234 return hid_actionv ("LoadFrom", argc, argv);
1236 function = argc ? argv[0] : (char *)"Layout";
1238 if (strcasecmp (function, "Netlist") == 0)
1240 name = ghid_dialog_file_select_open (_("Load netlist file"),
1241 &current_netlist_dir,
1242 Settings.FilePath);
1244 else if (strcasecmp (function, "ElementToBuffer") == 0)
1246 name = ghid_dialog_file_select_open (_("Load element to buffer"),
1247 &current_element_dir,
1248 Settings.LibraryTree);
1250 else if (strcasecmp (function, "LayoutToBuffer") == 0)
1252 name = ghid_dialog_file_select_open (_("Load layout file to buffer"),
1253 &current_layout_dir,
1254 Settings.FilePath);
1256 else if (strcasecmp (function, "Layout") == 0)
1258 name = ghid_dialog_file_select_open (_("Load layout file"),
1259 &current_layout_dir,
1260 Settings.FilePath);
1263 if (name)
1265 if (Settings.verbose)
1266 fprintf (stderr, "%s: Calling LoadFrom(%s, %s)\n", __FUNCTION__,
1267 function, name);
1268 hid_actionl ("LoadFrom", function, name, NULL);
1269 g_free (name);
1272 return 0;
1276 /* ---------------------------------------------------------------------- */
1277 static const char save_syntax[] =
1278 "Save()\n"
1279 "Save(Layout|LayoutAs)\n"
1280 "Save(AllConnections|AllUnusedPins|ElementConnections)\n"
1281 "Save(PasteBuffer)";
1283 static const char save_help[] =
1284 N_("Save layout and/or element data to a user-selected file.");
1286 /* %start-doc actions Save
1288 This action is a GUI front-end to the core's @code{SaveTo} action
1289 (@pxref{SaveTo Action}). If you happen to pass a filename, like
1290 @code{SaveTo}, then @code{SaveTo} is called directly. Else, the
1291 user is prompted for a filename to save, and then @code{SaveTo} is
1292 called with that filename.
1294 %end-doc */
1296 static int
1297 Save (int argc, char **argv, Coord x, Coord y)
1299 char *function;
1300 char *name;
1301 char *prompt;
1303 static gchar *current_dir = NULL;
1305 if (argc > 1)
1306 return hid_actionv ("SaveTo", argc, argv);
1308 function = argc ? argv[0] : (char *)"Layout";
1310 if (strcasecmp (function, "Layout") == 0)
1311 if (PCB->Filename)
1312 return hid_actionl ("SaveTo", "Layout", PCB->Filename, NULL);
1314 if (strcasecmp (function, "PasteBuffer") == 0)
1315 prompt = _("Save element as");
1316 else
1317 prompt = _("Save layout as");
1319 name = ghid_dialog_file_select_save (prompt,
1320 &current_dir,
1321 PCB->Filename, Settings.FilePath);
1323 if (name)
1325 if (Settings.verbose)
1326 fprintf (stderr, "%s: Calling SaveTo(%s, %s)\n",
1327 __FUNCTION__, function, name);
1329 if (strcasecmp (function, "PasteBuffer") == 0)
1330 hid_actionl ("PasteBuffer", "Save", name, NULL);
1331 else
1334 * if we got this far and the function is Layout, then
1335 * we really needed it to be a LayoutAs. Otherwise
1336 * ActionSaveTo() will ignore the new file name we
1337 * just obtained.
1339 if (strcasecmp (function, "Layout") == 0)
1340 hid_actionl ("SaveTo", "LayoutAs", name, NULL);
1341 else
1342 hid_actionl ("SaveTo", function, name, NULL);
1344 g_free (name);
1346 else
1348 return 1;
1351 return 0;
1354 /* ---------------------------------------------------------------------- */
1355 static const char swapsides_syntax[] =
1356 "SwapSides(|v|h|r)";
1358 static const char swapsides_help[] =
1359 N_("Swaps the side of the board you're looking at.");
1361 /* %start-doc actions SwapSides
1363 This action changes the way you view the board.
1365 @table @code
1367 @item v
1368 Flips the board over vertically (up/down).
1370 @item h
1371 Flips the board over horizontally (left/right), like flipping pages in
1372 a book.
1374 @item r
1375 Rotates the board 180 degrees without changing sides.
1377 @end table
1379 If no argument is given, the board isn't moved but the opposite side
1380 is shown.
1382 Normally, this action changes which pads and silk layer are drawn as
1383 true silk, and which are drawn as the "invisible" layer. It also
1384 determines which solder mask you see.
1386 As a special case, if the layer group for the side you're looking at
1387 is visible and currently active, and the layer group for the opposite
1388 is not visible (i.e. disabled), then this action will also swap which
1389 layer group is visible and active, effectively swapping the ``working
1390 side'' of the board.
1392 %end-doc */
1395 static int
1396 SwapSides (int argc, char **argv, Coord x, Coord y)
1398 int active_group = GetLayerGroupNumberByNumber (LayerStack[0]);
1399 int comp_group = GetLayerGroupNumberByNumber (component_silk_layer);
1400 int solder_group = GetLayerGroupNumberByNumber (solder_silk_layer);
1401 bool comp_on = LAYER_PTR (PCB->LayerGroups.Entries[comp_group][0])->On;
1402 bool solder_on = LAYER_PTR (PCB->LayerGroups.Entries[solder_group][0])->On;
1404 if (argc > 0)
1406 switch (argv[0][0]) {
1407 case 'h':
1408 case 'H':
1409 ghid_flip_view (gport->pcb_x, gport->pcb_y, true, false);
1410 break;
1411 case 'v':
1412 case 'V':
1413 ghid_flip_view (gport->pcb_x, gport->pcb_y, false, true);
1414 break;
1415 case 'r':
1416 case 'R':
1417 ghid_flip_view (gport->pcb_x, gport->pcb_y, true, true);
1418 Settings.ShowSolderSide = !Settings.ShowSolderSide; /* Swapped back below */
1419 break;
1420 default:
1421 return 1;
1425 Settings.ShowSolderSide = !Settings.ShowSolderSide;
1427 if ((active_group == comp_group && comp_on && !solder_on) ||
1428 (active_group == solder_group && solder_on && !comp_on))
1430 bool new_solder_vis = Settings.ShowSolderSide;
1432 ChangeGroupVisibility (PCB->LayerGroups.Entries[comp_group][0],
1433 !new_solder_vis, !new_solder_vis);
1434 ChangeGroupVisibility (PCB->LayerGroups.Entries[solder_group][0],
1435 new_solder_vis, new_solder_vis);
1438 return 0;
1441 /* ------------------------------------------------------------ */
1443 static const char print_syntax[] =
1444 "Print()";
1446 static const char print_help[] =
1447 N_("Print the layout.");
1449 /* %start-doc actions Print
1451 This will find the default printing HID, prompt the user for its
1452 options, and print the layout.
1454 %end-doc */
1456 static int
1457 Print (int argc, char **argv, Coord x, Coord y)
1459 HID **hids;
1460 int i;
1461 HID *printer = NULL;
1463 hids = hid_enumerate ();
1464 for (i = 0; hids[i]; i++)
1466 if (hids[i]->printer)
1467 printer = hids[i];
1470 if (printer == NULL)
1472 gui->log (_("Can't find a suitable printer HID"));
1473 return -1;
1476 /* check if layout is empty */
1477 if (!IsDataEmpty (PCB->Data))
1479 ghid_dialog_print (printer);
1481 else
1482 gui->log (_("Can't print empty layout"));
1484 return 0;
1488 /* ------------------------------------------------------------ */
1490 static HID_Attribute
1491 printer_calibrate_attrs[] = {
1492 {N_("Enter Values here:"), "",
1493 HID_Label, 0, 0, {0, 0, 0}, 0, 0},
1494 {N_("x-calibration"), N_("X scale for calibrating your printer"),
1495 HID_Real, 0.5, 25, {0, 0, 1.00}, 0, 0},
1496 {N_("y-calibration"), N_("Y scale for calibrating your printer"),
1497 HID_Real, 0.5, 25, {0, 0, 1.00}, 0, 0}
1499 static HID_Attr_Val printer_calibrate_values[3];
1501 static const char printcalibrate_syntax[] =
1502 "PrintCalibrate()";
1504 static const char printcalibrate_help[] =
1505 N_("Calibrate the printer.");
1507 /* %start-doc actions PrintCalibrate
1509 This will print a calibration page, which you would measure and type
1510 the measurements in, so that future printouts will be more precise.
1512 %end-doc */
1514 static int
1515 PrintCalibrate (int argc, char **argv, Coord x, Coord y)
1517 HID *printer = hid_find_printer ();
1518 printer->calibrate (0.0, 0.0);
1520 if (gui->attribute_dialog (printer_calibrate_attrs, 3,
1521 printer_calibrate_values,
1522 _("Printer Calibration Values"),
1523 _("Enter calibration values for your printer")))
1524 return 1;
1525 printer->calibrate (printer_calibrate_values[1].real_value,
1526 printer_calibrate_values[2].real_value);
1527 return 0;
1530 /* ------------------------------------------------------------ */
1532 static int
1533 Export (int argc, char **argv, Coord x, Coord y)
1536 /* check if layout is empty */
1537 if (!IsDataEmpty (PCB->Data))
1539 ghid_dialog_export ();
1541 else
1542 gui->log (_("Can't export empty layout"));
1544 return 0;
1547 /* ------------------------------------------------------------ */
1549 static int
1550 Benchmark (int argc, char **argv, Coord x, Coord y)
1552 int i = 0;
1553 time_t start, end;
1554 GdkDisplay *display;
1556 display = gdk_drawable_get_display (gport->drawable);
1558 gdk_display_sync (display);
1559 time (&start);
1562 ghid_invalidate_all ();
1563 gdk_window_process_updates (gtk_widget_get_window (gport->drawing_area),
1564 FALSE);
1565 time (&end);
1566 i++;
1568 while (end - start < 10);
1570 printf (_("%g redraws per second\n"), i / 10.0);
1572 return 0;
1575 /* ------------------------------------------------------------ */
1577 static const char center_syntax[] =
1578 "Center()\n";
1580 static const char center_help[] =
1581 N_("Moves the pointer to the center of the window.");
1583 /* %start-doc actions Center
1585 Move the pointer to the center of the window, but only if it's
1586 currently within the window already.
1588 %end-doc */
1590 static int
1591 Center(int argc, char **argv, Coord pcb_x, Coord pcb_y)
1593 GdkDisplay *display;
1594 GdkScreen *screen;
1595 int offset_x, offset_y;
1596 int widget_x, widget_y;
1597 int pointer_x, pointer_y;
1599 if (argc != 0)
1600 AFAIL (center);
1602 /* Aim to put the given x, y PCB coordinates in the center of the widget */
1603 widget_x = gport->width / 2;
1604 widget_y = gport->height / 2;
1606 ghid_pan_view_abs (pcb_x, pcb_y, widget_x, widget_y);
1608 /* Now move the mouse pointer to the place where the board location
1609 * actually ended up.
1611 * XXX: Should only do this if we confirm we are inside our window?
1614 ghid_pcb_to_event_coords (pcb_x, pcb_y, &widget_x, &widget_y);
1615 gdk_window_get_origin (gtk_widget_get_window (gport->drawing_area),
1616 &offset_x, &offset_y);
1618 pointer_x = offset_x + widget_x;
1619 pointer_y = offset_y + widget_y;
1621 display = gdk_display_get_default ();
1622 screen = gdk_display_get_default_screen (display);
1623 gdk_display_warp_pointer (display, screen, pointer_x, pointer_y);
1625 return 0;
1628 /* ------------------------------------------------------------ */
1629 static const char cursor_syntax[] =
1630 "Cursor(Type,DeltaUp,DeltaRight,Units)";
1632 static const char cursor_help[] =
1633 N_("Move the cursor.");
1635 /* %start-doc actions Cursor
1637 This action moves the mouse cursor. Unlike other actions which take
1638 coordinates, this action's coordinates are always relative to the
1639 user's view of the board. Thus, a positive @var{DeltaUp} may move the
1640 cursor towards the board origin if the board is inverted.
1642 Type is one of @samp{Pan} or @samp{Warp}. @samp{Pan} causes the
1643 viewport to move such that the crosshair is under the mouse cursor.
1644 @samp{Warp} causes the mouse cursor to move to be above the crosshair.
1646 @var{Units} can be one of the following:
1648 @table @samp
1650 @item mil
1651 @itemx mm
1652 The cursor is moved by that amount, in board units.
1654 @item grid
1655 The cursor is moved by that many grid points.
1657 @item view
1658 The values are percentages of the viewport's view. Thus, a pan of
1659 @samp{100} would scroll the viewport by exactly the width of the
1660 current view.
1662 @item board
1663 The values are percentages of the board size. Thus, a move of
1664 @samp{50,50} moves you halfway across the board.
1666 @end table
1668 %end-doc */
1670 static int
1671 CursorAction(int argc, char **argv, Coord x, Coord y)
1673 UnitList extra_units_x = {
1674 { "grid", PCB->Grid, 0 },
1675 { "view", gport->view.width, UNIT_PERCENT },
1676 { "board", PCB->MaxWidth, UNIT_PERCENT },
1677 { "", 0, 0 }
1679 UnitList extra_units_y = {
1680 { "grid", PCB->Grid, 0 },
1681 { "view", gport->view.height, UNIT_PERCENT },
1682 { "board", PCB->MaxHeight, UNIT_PERCENT },
1683 { "", 0, 0 }
1685 int pan_warp = HID_SC_DO_NOTHING;
1686 double dx, dy;
1688 if (argc != 4)
1689 AFAIL (cursor);
1691 if (strcasecmp (argv[0], "pan") == 0)
1692 pan_warp = HID_SC_PAN_VIEWPORT;
1693 else if (strcasecmp (argv[0], "warp") == 0)
1694 pan_warp = HID_SC_WARP_POINTER;
1695 else
1696 AFAIL (cursor);
1698 dx = GetValueEx (argv[1], argv[3], NULL, extra_units_x, "");
1699 if (gport->view.flip_x)
1700 dx = -dx;
1701 dy = GetValueEx (argv[2], argv[3], NULL, extra_units_y, "");
1702 if (!gport->view.flip_y)
1703 dy = -dy;
1705 EventMoveCrosshair (Crosshair.X + dx, Crosshair.Y + dy);
1706 gui->set_crosshair (Crosshair.X, Crosshair.Y, pan_warp);
1708 return 0;
1710 /* ------------------------------------------------------------ */
1712 static const char dowindows_syntax[] =
1713 "DoWindows(1|2|3|4|5|6)\n"
1714 "DoWindows(Layout|Library|Log|Netlist|Preferences|DRC)";
1716 static const char dowindows_help[] =
1717 N_("Open various GUI windows.");
1719 /* %start-doc actions DoWindows
1721 @table @code
1723 @item 1
1724 @itemx Layout
1725 Open the layout window. Since the layout window is always shown
1726 anyway, this has no effect.
1728 @item 2
1729 @itemx Library
1730 Open the library window.
1732 @item 3
1733 @itemx Log
1734 Open the log window.
1736 @item 4
1737 @itemx Netlist
1738 Open the netlist window.
1740 @item 5
1741 @itemx Preferences
1742 Open the preferences window.
1744 @item 6
1745 @itemx DRC
1746 Open the DRC violations window.
1748 @end table
1750 %end-doc */
1752 static int
1753 DoWindows (int argc, char **argv, Coord x, Coord y)
1755 char *a = argc == 1 ? argv[0] : (char *)"";
1757 if (strcmp (a, "1") == 0 || strcasecmp (a, "Layout") == 0)
1760 else if (strcmp (a, "2") == 0 || strcasecmp (a, "Library") == 0)
1762 ghid_library_window_show (gport, TRUE);
1764 else if (strcmp (a, "3") == 0 || strcasecmp (a, "Log") == 0)
1766 ghid_log_window_show (TRUE);
1768 else if (strcmp (a, "4") == 0 || strcasecmp (a, "Netlist") == 0)
1770 ghid_netlist_window_show (gport, TRUE);
1772 else if (strcmp (a, "5") == 0 || strcasecmp (a, "Preferences") == 0)
1774 ghid_config_window_show ();
1776 else if (strcmp (a, "6") == 0 || strcasecmp (a, "DRC") == 0)
1778 ghid_drc_window_show (TRUE);
1780 else
1782 AFAIL (dowindows);
1785 return 0;
1788 /* ------------------------------------------------------------ */
1789 static const char setunits_syntax[] =
1790 "SetUnits(mm|mil)";
1792 static const char setunits_help[] =
1793 N_("Set the default measurement units.");
1795 /* %start-doc actions SetUnits
1797 @table @code
1799 @item mil
1800 Sets the display units to mils (1/1000 inch).
1802 @item mm
1803 Sets the display units to millimeters.
1805 @end table
1807 %end-doc */
1809 static int
1810 SetUnits (int argc, char **argv, Coord x, Coord y)
1812 const Unit *new_unit;
1813 if (argc == 0)
1814 return 0;
1816 new_unit = get_unit_struct (argv[0]);
1817 if (new_unit != NULL && new_unit->allow != NO_PRINT)
1819 Settings.grid_unit = new_unit;
1820 Settings.increments = get_increments_struct (Settings.grid_unit->suffix);
1821 AttributePut (PCB, "PCB::grid::unit", argv[0]);
1824 ghid_config_handle_units_changed ();
1826 ghid_set_status_line_label ();
1828 /* FIXME ?
1829 * lesstif_sizes_reset ();
1830 * lesstif_styles_update_values ();
1832 return 0;
1835 /* ------------------------------------------------------------ */
1836 static const char scroll_syntax[] =
1837 "Scroll(up|down|left|right, [div])";
1839 static const char scroll_help[] =
1840 N_("Scroll the viewport.");
1842 /* % start-doc actions Scroll
1844 @item up|down|left|right
1845 Specifies the direction to scroll
1847 @item div
1848 Optional. Specifies how much to scroll by. The viewport is scrolled
1849 by 1/div of what is visible, so div = 1 scrolls a whole page. If not
1850 default is given, div=40.
1852 %end-doc */
1854 static int
1855 ScrollAction (int argc, char **argv, Coord x, Coord y)
1857 gdouble dx = 0.0, dy = 0.0;
1858 int div = 40;
1860 if (!ghidgui)
1861 return 0;
1863 if (argc != 1 && argc != 2)
1864 AFAIL (scroll);
1866 if (argc == 2)
1867 div = atoi(argv[1]);
1869 if (strcasecmp (argv[0], "up") == 0)
1870 dy = -gport->view.height / div;
1871 else if (strcasecmp (argv[0], "down") == 0)
1872 dy = gport->view.height / div;
1873 else if (strcasecmp (argv[0], "right") == 0)
1874 dx = gport->view.width / div;
1875 else if (strcasecmp (argv[0], "left") == 0)
1876 dx = -gport->view.width / div;
1877 else
1878 AFAIL (scroll);
1880 ghid_pan_view_rel (dx, dy);
1882 return 0;
1885 /* ------------------------------------------------------------ */
1886 static const char pan_syntax[] =
1887 "Pan([thumb], Mode)";
1889 static const char pan_help[] =
1890 N_("Start or stop panning (Mode = 1 to start, 0 to stop)\n"
1891 "Optional thumb argument is ignored for now in gtk hid.\n");
1893 /* %start-doc actions Pan
1895 Start or stop panning. To start call with Mode = 1, to stop call with
1896 Mode = 0. If the Mode is turned on and off with the cross hairs at
1897 the same coordinates, the auto pan mode is toggled.
1899 %end-doc */
1901 static int
1902 PanAction (int argc, char **argv, Coord x, Coord y)
1904 static int on_x, on_y;
1905 int mode;
1907 if (!ghidgui)
1908 return 0;
1910 if (argc != 1 && argc != 2)
1911 AFAIL (pan);
1913 if (argc == 1)
1914 mode = atoi(argv[0]);
1915 else
1917 mode = atoi(argv[1]);
1918 Message (_("The gtk gui currently ignores the optional first argument "
1919 "to the Pan action.\nFeel free to provide patches.\n"));
1922 gport->panning = mode;
1924 if (mode == 1)
1926 on_x = x;
1927 on_y = y;
1929 else if (x == on_x && y == on_y)
1931 notify_crosshair_change (false);
1932 ghidgui->auto_pan_on = !ghidgui->auto_pan_on;
1933 notify_crosshair_change (true);
1936 return 0;
1939 /* ------------------------------------------------------------ */
1940 static const char popup_syntax[] =
1941 "Popup(MenuName, [Button])";
1943 static const char popup_help[] =
1944 N_("Bring up the popup menu specified by @code{MenuName}.\n"
1945 "If called by a mouse event then the mouse button number\n"
1946 "must be specified as the optional second argument.");
1948 /* %start-doc actions Popup
1950 This just pops up the specified menu. The menu must have been defined
1951 as a named subresource of the Popups resource in the menu resource
1952 file.
1954 %end-doc */
1957 static int
1958 Popup (int argc, char **argv, Coord x, Coord y)
1960 GtkMenu *menu;
1962 if (argc != 1 && argc != 2)
1963 AFAIL (popup);
1965 menu = ghid_main_menu_get_popup (GHID_MAIN_MENU (ghidgui->menu_bar), argv[0]);
1966 if (! GTK_IS_MENU (menu))
1968 Message (_("The specified popup menu \"%s\" has not been defined.\n"), argv[0]);
1969 return 1;
1971 else
1973 ghidgui->in_popup = TRUE;
1974 gtk_widget_grab_focus (ghid_port.drawing_area);
1975 gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0,
1976 gtk_get_current_event_time());
1978 return 0;
1980 /* ------------------------------------------------------------ */
1981 static const char importgui_syntax[] =
1982 "ImportGUI()";
1984 static const char importgui_help[] =
1985 N_("Asks user which schematics to import into PCB.\n");
1987 /* %start-doc actions ImportGUI
1989 Asks user which schematics to import into PCB.
1991 %end-doc */
1994 static int
1995 ImportGUI (int argc, char **argv, Coord x, Coord y)
1997 char *name = NULL;
1998 static gchar *current_layout_dir = NULL;
1999 static int I_am_recursing = 0;
2000 int rv;
2002 if (I_am_recursing)
2003 return 1;
2006 name = ghid_dialog_file_select_open (_("Load schematics"),
2007 &current_layout_dir,
2008 Settings.FilePath);
2010 #ifdef DEBUG
2011 printf("File selected = %s\n", name);
2012 #endif
2014 AttributePut (PCB, "import::src0", name);
2015 free (name);
2017 I_am_recursing = 1;
2018 rv = hid_action ("Import");
2019 I_am_recursing = 0;
2021 return rv;
2024 /* ------------------------------------------------------------ */
2025 static int
2026 Busy (int argc, char **argv, Coord x, Coord y)
2028 ghid_watch_cursor ();
2029 return 0;
2032 HID_Action ghid_main_action_list[] = {
2033 {"About", 0, About, about_help, about_syntax},
2034 {"Benchmark", 0, Benchmark},
2035 {"Busy", 0, Busy},
2036 {"Center", N_("Click on a location to center"), Center, center_help, center_syntax},
2037 {"Command", 0, Command},
2038 {"Cursor", 0, CursorAction, cursor_help, cursor_syntax},
2039 {"DoWindows", 0, DoWindows, dowindows_help, dowindows_syntax},
2040 {"Export", 0, Export},
2041 {"GetXY", "", GetXY, getxy_help, getxy_syntax},
2042 {"ImportGUI", 0, ImportGUI, importgui_help, importgui_syntax},
2043 {"LayerGroupsChanged", 0, LayerGroupsChanged},
2044 {"LibraryChanged", 0, LibraryChanged},
2045 {"Load", 0, Load},
2046 {"Pan", N_("Click on a place to pan"), PanAction, pan_help, pan_syntax},
2047 {"PCBChanged", 0, PCBChanged},
2048 {"PointCursor", 0, PointCursor},
2049 {"Popup", 0, Popup, popup_help, popup_syntax},
2050 {"Print", 0, Print,
2051 print_help, print_syntax},
2052 {"PrintCalibrate", 0, PrintCalibrate,
2053 printcalibrate_help, printcalibrate_syntax},
2054 {"RouteStylesChanged", 0, RouteStylesChanged},
2055 {"Save", 0, Save, save_help, save_syntax},
2056 {"Scroll", N_("Click on a place to scroll"), ScrollAction, scroll_help, scroll_syntax},
2057 {"SetUnits", 0, SetUnits, setunits_help, setunits_syntax},
2058 {"SwapSides", 0, SwapSides, swapsides_help, swapsides_syntax},
2059 {"Zoom", N_("Click on zoom focus"), Zoom, zoom_help, zoom_syntax}
2062 REGISTER_ACTIONS (ghid_main_action_list)
2065 static int
2066 flag_flipx (int x)
2068 return gport->view.flip_x;
2071 static int
2072 flag_flipy (int x)
2074 return gport->view.flip_y;
2077 HID_Flag ghid_main_flag_list[] = {
2078 {"flip_x", flag_flipx, 0},
2079 {"flip_y", flag_flipy, 0}
2082 REGISTER_FLAGS (ghid_main_flag_list)
2084 #include "dolists.h"
2087 * We will need these for finding the windows installation
2088 * directory. Without that we can't find our fonts and
2089 * footprint libraries.
2091 #ifdef WIN32
2092 #include <windows.h>
2093 #include <winreg.h>
2094 #endif
2096 HID ghid_hid;
2098 void
2099 hid_gtk_init ()
2101 #ifdef WIN32
2102 char * tmps;
2103 char * share_dir;
2104 #endif
2106 #ifdef WIN32
2107 tmps = g_win32_get_package_installation_directory (PACKAGE "-" VERSION, NULL);
2108 #define REST_OF_PATH G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S PACKAGE
2109 share_dir = (char *) malloc(strlen(tmps) +
2110 strlen(REST_OF_PATH) +
2112 sprintf (share_dir, "%s%s", tmps, REST_OF_PATH);
2113 free (tmps);
2114 #undef REST_OF_PATH
2115 printf ("\"Share\" installation path is \"%s\"\n", share_dir);
2116 #endif
2118 memset (&ghid_hid, 0, sizeof (HID));
2120 common_nogui_init (&ghid_hid);
2121 common_draw_helpers_init (&ghid_hid);
2123 ghid_hid.struct_size = sizeof (HID);
2124 ghid_hid.name = "gtk";
2125 ghid_hid.description = "Gtk - The Gimp Toolkit";
2126 ghid_hid.gui = 1;
2127 ghid_hid.poly_after = 1;
2129 ghid_hid.get_export_options = ghid_get_export_options;
2130 ghid_hid.do_export = ghid_do_export;
2131 ghid_hid.parse_arguments = ghid_parse_arguments;
2132 ghid_hid.invalidate_lr = ghid_invalidate_lr;
2133 ghid_hid.invalidate_all = ghid_invalidate_all;
2134 ghid_hid.notify_crosshair_change = ghid_notify_crosshair_change;
2135 ghid_hid.notify_mark_change = ghid_notify_mark_change;
2136 ghid_hid.set_layer = ghid_set_layer;
2137 ghid_hid.make_gc = ghid_make_gc;
2138 ghid_hid.destroy_gc = ghid_destroy_gc;
2139 ghid_hid.use_mask = ghid_use_mask;
2140 ghid_hid.set_color = ghid_set_color;
2141 ghid_hid.set_line_cap = ghid_set_line_cap;
2142 ghid_hid.set_line_width = ghid_set_line_width;
2143 ghid_hid.set_draw_xor = ghid_set_draw_xor;
2144 ghid_hid.draw_line = ghid_draw_line;
2145 ghid_hid.draw_arc = ghid_draw_arc;
2146 ghid_hid.draw_rect = ghid_draw_rect;
2147 ghid_hid.fill_circle = ghid_fill_circle;
2148 ghid_hid.fill_polygon = ghid_fill_polygon;
2149 ghid_hid.fill_rect = ghid_fill_rect;
2151 ghid_hid.calibrate = ghid_calibrate;
2152 ghid_hid.shift_is_pressed = ghid_shift_is_pressed;
2153 ghid_hid.control_is_pressed = ghid_control_is_pressed;
2154 ghid_hid.mod1_is_pressed = ghid_mod1_is_pressed,
2155 ghid_hid.get_coords = ghid_get_coords;
2156 ghid_hid.set_crosshair = ghid_set_crosshair;
2157 ghid_hid.add_timer = ghid_add_timer;
2158 ghid_hid.stop_timer = ghid_stop_timer;
2159 ghid_hid.watch_file = ghid_watch_file;
2160 ghid_hid.unwatch_file = ghid_unwatch_file;
2161 ghid_hid.add_block_hook = ghid_add_block_hook;
2162 ghid_hid.stop_block_hook = ghid_stop_block_hook;
2164 ghid_hid.log = ghid_log;
2165 ghid_hid.logv = ghid_logv;
2166 ghid_hid.confirm_dialog = ghid_confirm_dialog;
2167 ghid_hid.close_confirm_dialog = ghid_close_confirm_dialog;
2168 ghid_hid.report_dialog = ghid_report_dialog;
2169 ghid_hid.prompt_for = ghid_prompt_for;
2170 ghid_hid.fileselect = ghid_fileselect;
2171 ghid_hid.attribute_dialog = ghid_attribute_dialog;
2172 ghid_hid.show_item = ghid_show_item;
2173 ghid_hid.beep = ghid_beep;
2174 ghid_hid.progress = ghid_progress;
2175 ghid_hid.drc_gui = &ghid_drc_gui,
2176 ghid_hid.edit_attributes = ghid_attributes;
2178 ghid_hid.request_debug_draw = ghid_request_debug_draw;
2179 ghid_hid.flush_debug_draw = ghid_flush_debug_draw;
2180 ghid_hid.finish_debug_draw = ghid_finish_debug_draw;
2182 ghid_hid.notify_save_pcb = ghid_notify_save_pcb;
2183 ghid_hid.notify_filename_changed = ghid_notify_filename_changed;
2185 hid_register_hid (&ghid_hid);
2186 #include "gtk_lists.h"