Merge the usermenu branch. This reworks how the menus and hotkeys
[geda-pcb/leaky.git] / src / hid / gtk / gtkhid-main.c
blobb1d8ab0c0705837b3178b8bf40b5e7dfff0b19cb
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 "data.h"
19 #include "draw.h"
20 #include "error.h"
21 #include "global.h"
22 #include "mymem.h"
23 #include "draw.h"
24 #include "clip.h"
26 #include "hid.h"
27 #include "../hidint.h"
28 #include "gui.h"
31 #if !GTK_CHECK_VERSION(2,8,0) && defined(HAVE_GDK_GDKX_H)
32 #include <gdk/gdkx.h>
33 #endif
35 #ifdef HAVE_LIBDMALLOC
36 #include <dmalloc.h>
37 #endif
40 RCSID ("$Id$");
43 extern HID ghid_hid;
46 static void zoom_to (double factor, int x, int y);
47 static void zoom_by (double factor, int x, int y);
49 /* Sets gport->u_gc to the "right" GC to use (wrt mask or window)
51 #define USE_GC(gc) if (!use_gc(gc)) return
53 static int cur_mask = -1;
54 static int mask_seq = 0;
56 int ghid_flip_x = 0, ghid_flip_y = 0;
58 /* ------------------------------------------------------------ */
60 /* Px converts view->pcb, Vx converts pcb->view */
62 static inline int
63 Vx (int x)
65 int rv;
66 if (ghid_flip_x)
67 rv = (PCB->MaxWidth - x - gport->view_x0) / gport->zoom + 0.5;
68 else
69 rv = (x - gport->view_x0) / gport->zoom + 0.5;
70 return rv;
73 static inline int
74 Vx2 (int x)
76 return (x - gport->view_x0) / gport->zoom + 0.5;
79 static inline int
80 Vy (int y)
82 int rv;
83 if (ghid_flip_y)
84 rv = (PCB->MaxHeight - y - gport->view_y0) / gport->zoom + 0.5;
85 else
86 rv = (y - gport->view_y0) / gport->zoom + 0.5;
87 return rv;
90 static inline int
91 Vy2 (int y)
93 return (y - gport->view_y0) / gport->zoom + 0.5;
96 static inline int
97 Vz (int z)
99 return z / gport->zoom + 0.5;
102 static inline int
103 Px (int x)
105 int rv = x * gport->zoom + gport->view_x0;
106 if (ghid_flip_x)
107 rv = PCB->MaxWidth - (x * gport->zoom + gport->view_x0);
108 return rv;
111 static inline int
112 Py (int y)
114 int rv = y * gport->zoom + gport->view_y0;
115 if (ghid_flip_y)
116 rv = PCB->MaxHeight - (y * gport->zoom + gport->view_y0);
117 return rv;
120 /* ------------------------------------------------------------ */
122 static const char zoom_syntax[] =
123 "Zoom()\n"
124 "Zoom(factor)";
127 static const char zoom_help[] =
128 "Various zoom factor changes.";
130 /* %start-doc actions Zoom
131 Changes the zoom (magnification) of the view of the board. If no
132 arguments are passed, the view is scaled such that the board just fits
133 inside the visible window (i.e. ``view all''). Otherwise,
134 @var{factor} specifies a change in zoom factor. It may be prefixed by
135 @code{+}, @code{-}, or @code{=} to change how the zoom factor is
136 modified. The @var{factor} is a floating point number, such as
137 @code{1.5} or @code{0.75}.
139 @table @code
141 @item +@var{factor}
142 Values greater than 1.0 cause the board to be drawn smaller; more of
143 the board will be visible. Values between 0.0 and 1.0 cause the board
144 to be drawn bigger; less of the board will be visible.
146 @item -@var{factor}
147 Values greater than 1.0 cause the board to be drawn bigger; less of
148 the board will be visible. Values between 0.0 and 1.0 cause the board
149 to be drawn smaller; more of the board will be visible.
151 @item =@var{factor}
153 The @var{factor} is an absolute zoom factor; the unit for this value
154 is "PCB units per screen pixel". Since PCB units are 0.01 mil, a
155 @var{factor} of 1000 means 10 mils (0.01 in) per pixel, or 100 DPI,
156 about the actual resolution of most screens - resulting in an "actual
157 size" board. Similarly, a @var{factor} of 100 gives you a 10x actual
158 size.
160 @end table
162 Note that zoom factors of zero are silently ignored.
166 %end-doc */
168 static int
169 Zoom (int argc, char **argv, int x, int y)
171 double factor;
172 const char *vp;
173 double v;
175 if (argc > 1)
176 AFAIL (zoom);
178 if (x == 0 && y == 0)
180 x = gport->view_width / 2;
181 y = gport->view_height / 2;
183 else
185 /* Px converts view->pcb, Vx converts pcb->view */
186 x = Vx (x);
187 y = Vy (y);
190 if (argc < 1)
192 zoom_to (1000000, 0, 0);
193 return 0;
196 vp = argv[0];
197 if (*vp == '+' || *vp == '-' || *vp == '=')
198 vp++;
199 v = strtod (vp, 0);
200 if (v <= 0)
201 return 1;
202 switch (argv[0][0])
204 case '-':
205 factor = 1 / v;
206 zoom_by (1 / v, x, y);
207 break;
208 default:
209 case '+':
210 factor = v;
211 zoom_by (v, x, y);
212 break;
213 case '=':
214 /* this needs to set the scale factor absolutely*/
215 factor = 1.0;
216 zoom_to (v, x, y);
217 break;
220 return 0;
224 static void
225 zoom_to (double new_zoom, int x, int y)
227 double max_zoom, xfrac, yfrac;
228 int cx, cy;
230 /* gport->zoom:
231 * zoom value is PCB units per screen pixel. Larger numbers mean zooming
232 * out - the largest value means you are looking at the whole board.
234 * PCB units per screen pixel
236 * gport->view_width and gport->view_height are in PCB coordinates
239 #ifdef DEBUG
240 printf ("\nzoom_to( %g, %d, %d)\n", new_zoom, x, y);
241 #endif
243 xfrac = (double) x / (double) gport->view_width;
244 yfrac = (double) y / (double) gport->view_height;
246 if (ghid_flip_x)
247 xfrac = 1-xfrac;
248 if (ghid_flip_y)
249 yfrac = 1-yfrac;
251 /* Find the zoom that would just make the entire board fit */
252 max_zoom = PCB->MaxWidth / gport->width;
253 if (max_zoom < PCB->MaxHeight / gport->height)
254 max_zoom = PCB->MaxHeight / gport->height;
256 #ifdef DEBUG
257 printf ("zoom_to(): max_zoom = %g\n", max_zoom);
258 #endif
261 * clip the zooming so we can never have more than 1 pixel per PCB
262 * unit and never zoom out more than viewing the entire board
265 if (new_zoom < 1)
266 new_zoom = 1;
267 if (new_zoom > max_zoom)
268 new_zoom = max_zoom;
270 #ifdef DEBUG
271 printf ("max_zoom = %g, xfrac = %g, yfrac = %g, new_zoom = %g\n",
272 max_zoom, xfrac, yfrac, new_zoom);
273 #endif
275 /* find center x and y */
276 cx = gport->view_x0 + gport->view_width * xfrac * gport->zoom;
277 cy = gport->view_y0 + gport->view_height * yfrac * gport->zoom;
279 #ifdef DEBUG
280 printf ("zoom_to(): x0 = %d, cx = %d\n", gport->view_x0, cx);
281 printf ("zoom_to(): y0 = %d, cy = %d\n", gport->view_y0, cy);
282 #endif
284 if (gport->zoom != new_zoom)
286 gdouble xtmp, ytmp;
287 gint x0, y0;
289 xtmp = (gport->view_x - gport->view_x0) / (gdouble) gport->view_width;
290 ytmp = (gport->view_y - gport->view_y0) / (gdouble) gport->view_height;
292 gport->zoom = new_zoom;
293 pixel_slop = new_zoom;
294 ghid_port_ranges_scale(FALSE);
296 x0 = gport->view_x - xtmp * gport->view_width;
297 if (x0 < 0)
298 x0 = 0;
299 gport->view_x0 = x0;
301 y0 = gport->view_y - ytmp * gport->view_height;
302 if (y0 < 0)
303 y0 = 0;
304 gport->view_y0 = y0;
306 ghidgui->adjustment_changed_holdoff = TRUE;
307 gtk_range_set_value (GTK_RANGE (ghidgui->h_range), gport->view_x0);
308 gtk_range_set_value (GTK_RANGE (ghidgui->v_range), gport->view_y0);
309 ghidgui->adjustment_changed_holdoff = FALSE;
311 ghid_port_ranges_changed();
314 #ifdef DEBUG
315 printf ("zoom_to(): new x0 = %d\n", gport->view_x0);
316 printf ("zoom_to(): new y0 = %d\n", gport->view_y0);
317 #endif
318 ghid_set_status_line_label ();
321 void
322 zoom_by (double factor, int x, int y)
324 #ifdef DEBUG
325 printf ("\nzoom_by( %g, %d, %d). old gport->zoom = %g\n",
326 factor, x, y, gport->zoom);
327 #endif
328 zoom_to (gport->zoom * factor, x, y);
331 /* ------------------------------------------------------------ */
333 static void
334 draw_grid ()
336 static GdkPoint *points = 0;
337 static int npoints = 0;
338 int x1, y1, x2, y2, n, i;
339 double x, y;
341 if (!Settings.DrawGrid)
342 return;
343 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
344 return;
345 if (!gport->grid_gc)
347 if (gdk_color_parse (Settings.GridColor, &gport->grid_color))
349 gport->grid_color.red ^= gport->bg_color.red;
350 gport->grid_color.green ^= gport->bg_color.green;
351 gport->grid_color.blue ^= gport->bg_color.blue;
352 gdk_color_alloc (gport->colormap, &gport->grid_color);
354 gport->grid_gc = gdk_gc_new (gport->drawable);
355 gdk_gc_set_function (gport->grid_gc, GDK_XOR);
356 gdk_gc_set_foreground (gport->grid_gc, &gport->grid_color);
358 x1 = GRIDFIT_X (SIDE_X (gport->view_x0), PCB->Grid);
359 y1 = GRIDFIT_Y (SIDE_Y (gport->view_y0), PCB->Grid);
360 x2 = GRIDFIT_X (SIDE_X (gport->view_x0 + gport->view_width - 1), PCB->Grid);
361 y2 = GRIDFIT_Y (SIDE_Y (gport->view_y0 + gport->view_height - 1), PCB->Grid);
362 if (x1 > x2)
364 int tmp = x1;
365 x1 = x2;
366 x2 = tmp;
368 if (y1 > y2)
370 int tmp = y1;
371 y1 = y2;
372 y2 = tmp;
374 if (Vx (x1) < 0)
375 x1 += PCB->Grid;
376 if (Vy (y1) < 0)
377 y1 += PCB->Grid;
378 if (Vx (x2) >= gport->width)
379 x2 -= PCB->Grid;
380 if (Vy (y2) >= gport->height)
381 y2 -= PCB->Grid;
382 n = (int) ((x2 - x1) / PCB->Grid + 0.5) + 1;
383 if (n > npoints)
385 npoints = n + 10;
386 points =
387 MyRealloc (points, npoints * sizeof (GdkPoint), "gtk_draw_grid");
389 n = 0;
390 for (x = x1; x <= x2; x += PCB->Grid)
392 points[n].x = Vx (x);
393 n++;
395 for (y = y1; y <= y2; y += PCB->Grid)
397 int vy = Vy (y);
398 for (i = 0; i < n; i++)
399 points[i].y = vy;
400 gdk_draw_points (gport->drawable, gport->grid_gc, points, n);
404 /* ------------------------------------------------------------ */
406 HID_Attribute *
407 ghid_get_export_options (int *n_ret)
409 return NULL;
413 void
414 ghid_invalidate_wh (int x, int y, int width, int height, int last)
416 ghid_invalidate_all ();
419 void
420 ghid_invalidate_lr (int left, int right, int top, int bottom, int last)
422 ghid_invalidate_all ();
425 static void
426 ghid_draw_bg_image(void)
428 static GdkPixbuf *pixbuf;
429 GdkInterpType interp_type;
430 gint x, y, w, h, w_src, h_src;
431 static gint w_scaled, h_scaled;
433 if (!ghidgui->bg_pixbuf)
434 return;
436 w = PCB->MaxWidth / gport->zoom;
437 h = PCB->MaxHeight / gport->zoom;
438 x = gport->view_x0 / gport->zoom;
439 y = gport->view_y0 / gport->zoom;
441 if (w_scaled != w || h_scaled != h)
443 if (pixbuf)
444 g_object_unref(G_OBJECT(pixbuf));
446 w_src = gdk_pixbuf_get_width(ghidgui->bg_pixbuf);
447 h_src = gdk_pixbuf_get_height(ghidgui->bg_pixbuf);
448 if (w > w_src && h > h_src)
449 interp_type = GDK_INTERP_NEAREST;
450 else
451 interp_type = GDK_INTERP_BILINEAR;
453 pixbuf = gdk_pixbuf_scale_simple(ghidgui->bg_pixbuf, w, h, interp_type);
454 w_scaled = w;
455 h_scaled = h;
457 if (pixbuf)
458 gdk_pixbuf_render_to_drawable(pixbuf, gport->drawable, gport->bg_gc,
459 x, y, 0, 0,
460 w - x, h - y, GDK_RGB_DITHER_NORMAL, 0, 0);
463 void
464 ghid_invalidate_all ()
466 int eleft, eright, etop, ebottom;
467 BoxType region;
469 if (!gport->pixmap)
470 return;
472 region.X1 = MIN(Px(0), Px(gport->width + 1));
473 region.Y1 = MIN(Py(0), Py(gport->height + 1));
474 region.X2 = MAX(Px(0), Px(gport->width + 1));
475 region.Y2 = MAX(Py(0), Py(gport->height + 1));
477 eleft = Vx (0);
478 eright = Vx (PCB->MaxWidth);
479 etop = Vy (0);
480 ebottom = Vy (PCB->MaxHeight);
481 if (eleft > eright)
483 int tmp = eleft;
484 eleft = eright;
485 eright = tmp;
487 if (etop > ebottom)
489 int tmp = etop;
490 etop = ebottom;
491 ebottom = tmp;
494 if (eleft > 0)
495 gdk_draw_rectangle (gport->drawable, gport->offlimits_gc,
496 1, 0, 0, eleft, gport->height);
497 else
498 eleft = 0;
499 if (eright < gport->width)
500 gdk_draw_rectangle (gport->drawable, gport->offlimits_gc,
501 1, eright, 0, gport->width - eright, gport->height);
502 else
503 eright = gport->width;
504 if (etop > 0)
505 gdk_draw_rectangle (gport->drawable, gport->offlimits_gc,
506 1, eleft, 0, eright - eleft + 1, etop);
507 else
508 etop = 0;
509 if (ebottom < gport->height)
510 gdk_draw_rectangle (gport->drawable, gport->offlimits_gc,
511 1, eleft, ebottom, eright - eleft + 1,
512 gport->height - ebottom);
513 else
514 ebottom = gport->height;
516 gdk_draw_rectangle (gport->drawable, gport->bg_gc, 1,
517 eleft, etop, eright - eleft + 1, ebottom - etop + 1);
519 ghid_draw_bg_image();
521 hid_expose_callback (&ghid_hid, &region, 0);
522 draw_grid ();
523 if (ghidgui->need_restore_crosshair)
524 RestoreCrosshair (FALSE);
525 ghidgui->need_restore_crosshair = FALSE;
526 ghid_screen_update ();
530 void
531 ghid_pinout_redraw (PinoutType * po)
533 double save_zoom;
534 int da_w, da_h, save_left, save_top, save_width, save_height;
535 double xz, yz;
537 GdkWindow *window = po->drawing_area->window;
538 GdkDrawable *save_drawable;
540 if (!window)
541 return;
543 save_zoom = gport->zoom;
544 save_left = gport->view_x0;
545 save_top = gport->view_y0;
546 save_width = gport->view_width;
547 save_height = gport->view_height;
549 /* Setup drawable and zoom factor for drawing routines
551 save_drawable = gport->drawable;
553 gdk_window_get_geometry (window, 0, 0, &da_w, &da_h, 0);
554 xz = (double) po->x_max / da_w;
555 yz = (double) po->y_max / da_h;
556 if (xz > yz)
557 gport->zoom = xz;
558 else
559 gport->zoom = yz;
561 gport->drawable = window;
562 gport->view_x0 = gport->view_y0 = 0;
563 gport->view_width = da_w * gport->zoom;
564 gport->view_height = da_h * gport->zoom;
566 /* clear background call the drawing routine */
567 gdk_draw_rectangle (window, gport->bg_gc, TRUE, 0, 0, MAX_COORD, MAX_COORD);
569 DrawElement (&po->element, 0);
571 gport->zoom = save_zoom;
572 gport->drawable = save_drawable;
573 gport->view_x0 = save_left;
574 gport->view_y0 = save_top;
575 gport->view_width = save_width;;
576 gport->view_height = save_height;
580 ghid_set_layer (const char *name, int group)
582 int idx = (group >= 0
583 && group <
584 max_layer) ? PCB->LayerGroups.Entries[group][0] : group;
586 if (idx >= 0 && idx < max_layer + 2)
587 return /*pinout ? 1 : */ PCB->Data->Layer[idx].On;
588 if (idx < 0)
590 switch (SL_TYPE (idx))
592 case SL_INVISIBLE:
593 return /* pinout ? 0 : */ PCB->InvisibleObjectsOn;
594 case SL_MASK:
595 if (SL_MYSIDE (idx) /*&& !pinout */ )
596 return TEST_FLAG (SHOWMASKFLAG, PCB);
597 return 0;
598 case SL_SILK:
599 if (SL_MYSIDE (idx) /*|| pinout */ )
600 return PCB->ElementOn;
601 return 0;
602 case SL_ASSY:
603 return 0;
604 case SL_PDRILL:
605 case SL_UDRILL:
606 return 1;
609 return 0;
612 #define WHICH_GC(gc) (cur_mask == HID_MASK_CLEAR ? gport->mask_gc : (gc)->gc)
614 void
615 ghid_use_mask (int use_it)
617 static int mask_seq_id = 0;
618 GdkColor color;
620 if (!gport->pixmap)
621 return;
622 if (use_it == cur_mask)
623 return;
624 switch (use_it)
626 case HID_MASK_OFF:
627 gport->drawable = gport->pixmap;
628 mask_seq = 0;
629 break;
631 case HID_MASK_BEFORE:
632 printf ("gtk doesn't support mask_before!\n");
633 abort ();
635 case HID_MASK_CLEAR:
636 if (!gport->mask)
637 gport->mask = gdk_pixmap_new (0, gport->width, gport->height, 1);
638 gport->drawable = gport->mask;
639 mask_seq = 0;
640 if (!gport->mask_gc)
642 gport->mask_gc = gdk_gc_new (gport->drawable);
644 color.pixel = 1;
645 gdk_gc_set_foreground (gport->mask_gc, &color);
646 gdk_draw_rectangle (gport->drawable, gport->mask_gc, TRUE, 0, 0,
647 gport->width, gport->height);
648 color.pixel = 0;
649 gdk_gc_set_foreground (gport->mask_gc, &color);
650 break;
652 case HID_MASK_AFTER:
653 mask_seq_id++;
654 if (!mask_seq_id)
655 mask_seq_id = 1;
656 mask_seq = mask_seq_id;
658 gport->drawable = gport->pixmap;
659 break;
662 cur_mask = use_it;
665 void
666 ghid_extents_use_mask (int use_it)
671 typedef struct
673 int color_set;
674 GdkColor color;
675 int xor_set;
676 GdkColor xor_color;
677 } ColorCache;
680 /* Config helper functions for when the user changes color preferences.
681 | set_special colors used in the gtkhid.
683 static void
684 set_special_grid_color (void)
686 if (!gport->colormap)
687 return;
688 gport->grid_color.red ^= gport->bg_color.red;
689 gport->grid_color.green ^= gport->bg_color.green;
690 gport->grid_color.blue ^= gport->bg_color.blue;
691 gdk_color_alloc (gport->colormap, &gport->grid_color);
692 if (gport->grid_gc)
693 gdk_gc_set_foreground (gport->grid_gc, &gport->grid_color);
696 void
697 ghid_set_special_colors (HID_Attribute * ha)
699 if (!ha->name || !ha->value)
700 return;
701 if (!strcmp (ha->name, "background-color") && gport->bg_gc)
703 ghid_map_color_string (*(char **) ha->value, &gport->bg_color);
704 gdk_gc_set_foreground (gport->bg_gc, &gport->bg_color);
705 set_special_grid_color ();
707 else if (!strcmp (ha->name, "off-limit-color") && gport->offlimits_gc)
709 ghid_map_color_string (*(char **) ha->value, &gport->offlimits_color);
710 gdk_gc_set_foreground (gport->offlimits_gc, &gport->offlimits_color);
712 else if (!strcmp (ha->name, "grid-color") && gport->grid_gc)
714 ghid_map_color_string (*(char **) ha->value, &gport->grid_color);
715 set_special_grid_color ();
719 void
720 ghid_set_color (hidGC gc, const char *name)
722 static void *cache = 0;
723 hidval cval;
725 if (name == NULL)
727 fprintf (stderr, "%s(): name = NULL, setting to magenta\n",
728 __FUNCTION__);
729 name = "magenta";
732 gc->colorname = (char *) name;
733 if (!gc->gc)
734 return;
735 if (gport->colormap == 0)
736 gport->colormap = gtk_widget_get_colormap (gport->top_window);
738 if (strcmp (name, "erase") == 0)
740 gdk_gc_set_foreground (gc->gc, &gport->bg_color);
741 gc->erase = 1;
743 else if (strcmp (name, "drill") == 0)
745 gdk_gc_set_foreground (gc->gc, &gport->offlimits_color);
746 gc->erase = 0;
748 else
750 ColorCache *cc;
751 if (hid_cache_color (0, name, &cval, &cache))
752 cc = (ColorCache *) cval.ptr;
753 else
755 cc = (ColorCache *) malloc (sizeof (ColorCache));
756 memset (cc, 0, sizeof (*cc));
757 cval.ptr = cc;
758 hid_cache_color (1, name, &cval, &cache);
761 if (!cc->color_set)
763 if (gdk_color_parse (name, &cc->color))
764 gdk_color_alloc (gport->colormap, &cc->color);
765 else
766 gdk_color_white (gport->colormap, &cc->color);
767 cc->color_set = 1;
769 if (gc->xor)
771 if (!cc->xor_set)
773 cc->xor_color.red = cc->color.red ^ gport->bg_color.red;
774 cc->xor_color.green = cc->color.green ^ gport->bg_color.green;
775 cc->xor_color.blue = cc->color.blue ^ gport->bg_color.blue;
776 gdk_color_alloc (gport->colormap, &cc->xor_color);
777 cc->xor_set = 1;
779 gdk_gc_set_foreground (gc->gc, &cc->xor_color);
781 else
783 gdk_gc_set_foreground (gc->gc, &cc->color);
786 gc->erase = 0;
790 void
791 ghid_set_line_cap (hidGC gc, EndCapStyle style)
794 switch (style)
796 case Trace_Cap:
797 case Round_Cap:
798 gc->cap = GDK_CAP_ROUND;
799 gc->join = GDK_JOIN_ROUND;
800 break;
801 case Square_Cap:
802 case Beveled_Cap:
803 gc->cap = GDK_CAP_PROJECTING;
804 gc->join = GDK_JOIN_MITER;
805 break;
807 if (gc->gc)
808 gdk_gc_set_line_attributes (WHICH_GC (gc),
809 Vz (gc->width), GDK_LINE_SOLID,
810 gc->cap, gc->join);
813 void
814 ghid_set_line_width (hidGC gc, int width)
817 gc->width = width;
818 if (gc->gc)
819 gdk_gc_set_line_attributes (WHICH_GC (gc),
820 Vz (gc->width), GDK_LINE_SOLID,
821 gc->cap, gc->join);
824 void
825 ghid_set_draw_xor (hidGC gc, int xor)
827 gc->xor = xor;
828 if (!gc->gc)
829 return;
830 gdk_gc_set_function (gc->gc, xor ? GDK_XOR : GDK_COPY);
831 ghid_set_color (gc, gc->colorname);
834 void
835 ghid_set_draw_faded (hidGC gc, int faded)
837 printf ("ghid_set_draw_faded(%p,%d) -- not implemented\n", gc, faded);
840 void
841 ghid_set_line_cap_angle (hidGC gc, int x1, int y1, int x2, int y2)
843 printf ("ghid_set_line_cap_angle() -- not implemented\n");
846 static int
847 use_gc (hidGC gc)
849 if (!gport->pixmap)
850 return 0;
851 if (!gc->gc)
853 gc->gc = gdk_gc_new (gport->top_window->window);
854 ghid_set_color (gc, gc->colorname);
855 ghid_set_line_width (gc, gc->width);
856 ghid_set_line_cap (gc, gc->cap);
857 ghid_set_draw_xor (gc, gc->xor);
859 if (gc->mask_seq != mask_seq)
861 if (mask_seq)
862 gdk_gc_set_clip_mask (gc->gc, gport->mask);
863 else
864 gdk_gc_set_clip_mask (gc->gc, NULL);
865 gc->mask_seq = mask_seq;
867 gport->u_gc = WHICH_GC (gc);
868 return 1;
871 void
872 ghid_draw_line (hidGC gc, int x1, int y1, int x2, int y2)
874 double dx1, dy1, dx2, dy2;
876 dx1 = Vx ((double)x1);
877 dy1 = Vy ((double)y1);
878 dx2 = Vx ((double)x2);
879 dy2 = Vy ((double)y2);
881 if (! ClipLine (0, 0, gport->width, gport->height,
882 &dx1, &dy1, &dx2, &dy2, gc->width / gport->zoom))
883 return;
885 USE_GC (gc);
886 gdk_draw_line (gport->drawable, gport->u_gc, dx1, dy1, dx2, dy2);
889 void
890 ghid_draw_arc (hidGC gc, int cx, int cy,
891 int xradius, int yradius, int start_angle, int delta_angle)
893 gint vrx, vry;
894 gint w, h, radius;
896 w = gport->width * gport->zoom;
897 h = gport->height * gport->zoom;
898 radius = (xradius > yradius) ? xradius : yradius;
899 if (SIDE_X (cx) < gport->view_x0 - radius
900 || SIDE_X (cx) > gport->view_x0 + w + radius
901 || SIDE_Y (cy) < gport->view_y0 - radius
902 || SIDE_Y (cy) > gport->view_y0 + h + radius)
903 return;
905 USE_GC (gc);
906 vrx = Vz (xradius);
907 vry = Vz (yradius);
910 /* make sure we fall in the -180 to +180 range */
911 start_angle = (start_angle + 360 + 180) % 360 - 180;
912 if (ghid_flip_x)
914 start_angle = 180 - start_angle;
915 delta_angle = - delta_angle;
917 if (ghid_flip_y)
919 start_angle = - start_angle;
920 delta_angle = - delta_angle;
923 gdk_draw_arc (gport->drawable, gport->u_gc, 0,
924 Vx (cx) - vrx, Vy (cy) - vry,
925 vrx * 2, vry * 2, (start_angle + 180) * 64, delta_angle * 64);
928 void
929 ghid_draw_rect (hidGC gc, int x1, int y1, int x2, int y2)
931 gint w, h, lw;
933 lw = gc->width;
934 w = gport->width * gport->zoom;
935 h = gport->height * gport->zoom;
937 if ((SIDE_X (x1) < gport->view_x0 - lw
938 && SIDE_X (x2) < gport->view_x0 - lw)
939 || (SIDE_X (x1) > gport->view_x0 + w + lw
940 && SIDE_X (x2) > gport->view_x0 + w + lw)
941 || (SIDE_Y (y1) < gport->view_y0 - lw
942 && SIDE_Y (y2) < gport->view_y0 - lw)
943 || (SIDE_Y (y1) > gport->view_y0 + h + lw
944 && SIDE_Y (y2) > gport->view_y0 + h + lw))
945 return;
947 x1 = Vx (x1);
948 y1 = Vy (y1);
949 x2 = Vx (x2);
950 y2 = Vy (y2);
952 if (x1 > x2) { gint xt = x1; x1 = x2; x2 = xt; }
953 if (y1 > y2) { gint yt = y1; y1 = y2; y2 = yt; }
955 USE_GC (gc);
956 gdk_draw_rectangle (gport->drawable, gport->u_gc, FALSE,
957 x1, y1, x2 - x1 + 1, y2 - y1 + 1);
961 void
962 ghid_fill_circle (hidGC gc, int cx, int cy, int radius)
964 gint w, h, vr;
966 w = gport->width * gport->zoom;
967 h = gport->height * gport->zoom;
968 if (SIDE_X (cx) < gport->view_x0 - radius
969 || SIDE_X (cx) > gport->view_x0 + w + radius
970 || SIDE_Y (cy) < gport->view_y0 - radius
971 || SIDE_Y (cy) > gport->view_y0 + h + radius)
972 return;
974 USE_GC (gc);
975 vr = Vz (radius);
976 gdk_draw_arc (gport->drawable, gport->u_gc, TRUE,
977 Vx (cx) - vr, Vy (cy) - vr,
978 vr * 2, vr * 2, 0, 360 * 64);
981 void
982 ghid_fill_polygon (hidGC gc, int n_coords, int *x, int *y)
984 static GdkPoint *points = 0;
985 static int npoints = 0;
986 int i;
987 USE_GC (gc);
989 if (npoints < n_coords)
991 npoints = n_coords + 1;
992 points = MyRealloc (points,
993 npoints * sizeof (GdkPoint), (char *) __FUNCTION__);
995 for (i = 0; i < n_coords; i++)
997 points[i].x = Vx (x[i]);
998 points[i].y = Vy (y[i]);
1000 gdk_draw_polygon (gport->drawable, gport->u_gc, 1, points, n_coords);
1003 void
1004 ghid_fill_rect (hidGC gc, int x1, int y1, int x2, int y2)
1006 gint w, h, lw, xx;
1008 lw = gc->width;
1009 w = gport->width * gport->zoom;
1010 h = gport->height * gport->zoom;
1012 if ((SIDE_X (x1) < gport->view_x0 - lw
1013 && SIDE_X (x2) < gport->view_x0 - lw)
1014 || (SIDE_X (x1) > gport->view_x0 + w + lw
1015 && SIDE_X (x2) > gport->view_x0 + w + lw)
1016 || (SIDE_Y (y1) < gport->view_y0 - lw
1017 && SIDE_Y (y2) < gport->view_y0 - lw)
1018 || (SIDE_Y (y1) > gport->view_y0 + h + lw
1019 && SIDE_Y (y2) > gport->view_y0 + h + lw))
1020 return;
1022 x1 = Vx (x1);
1023 y1 = Vy (y1);
1024 x2 = Vx (x2);
1025 y2 = Vy (y2);
1026 if (x2 < x1)
1028 xx = x1;
1029 x1 = x2;
1030 x2 = xx;
1032 USE_GC (gc);
1033 gdk_draw_rectangle (gport->drawable, gport->u_gc, TRUE,
1034 x1, y1, x2 - x1 + 1, y2 - y1 + 1);
1037 void
1038 ghid_extents_draw_line (hidGC gc, int x1, int y1, int x2, int y2)
1040 printf ("ghid_extents_draw_line() -- not implemented\n");
1043 void
1044 ghid_extents_draw_arc (hidGC gc, int cx, int cy,
1045 int xradius, int yradius,
1046 int start_angle, int delta_angle)
1048 printf ("ghid_extents_draw_arc() -- not implemented\n");
1051 void
1052 ghid_extents_draw_rect (hidGC gc, int x1, int y1, int x2, int y2)
1054 printf ("ghid_extents_draw_rect() -- not implemented\n");
1057 void
1058 ghid_extents_fill_circle (hidGC gc, int cx, int cy, int radius)
1060 printf ("ghid_extents_fill_circle() -- not implemented\n");
1063 void
1064 ghid_extents_fill_polygon (hidGC gc, int n_coords, int *x, int *y)
1066 printf ("ghid_extents_fill_polygon() -- not implemented\n");
1069 void
1070 ghid_extents_fill_rect (hidGC gc, int x1, int y1, int x2, int y2)
1072 printf ("ghid_extents_fill_rect() -- not implemented\n");
1075 void
1076 ghid_calibrate (double xval, double yval)
1078 printf ("ghid_calibrate() -- not implemented\n");
1082 ghid_shift_is_pressed ()
1084 GdkModifierType mask;
1085 GHidPort *out = &ghid_port;
1087 gdk_window_get_pointer (out->drawing_area->window, NULL, NULL, &mask);
1088 return (mask & GDK_SHIFT_MASK) ? TRUE : FALSE;
1092 ghid_control_is_pressed ()
1094 GdkModifierType mask;
1095 GHidPort *out = &ghid_port;
1097 gdk_window_get_pointer (out->drawing_area->window, NULL, NULL, &mask);
1098 return (mask & GDK_CONTROL_MASK) ? TRUE : FALSE;
1101 void
1102 ghid_set_crosshair (int x, int y, int action)
1104 ghid_set_cursor_position_labels ();
1105 gport->x_crosshair = x;
1106 gport->y_crosshair = y;
1109 typedef struct
1111 void (*func) ();
1112 gint id;
1113 hidval user_data;
1115 GuiTimer;
1117 /* We need a wrapper around the hid timer because a gtk timer needs
1118 | to return FALSE else the timer will be restarted.
1120 static gboolean
1121 ghid_timer (GuiTimer * timer)
1123 (*timer->func) (timer->user_data);
1124 ghid_mode_cursor (Settings.Mode);
1125 return FALSE; /* Turns timer off */
1128 hidval
1129 ghid_add_timer (void (*func) (hidval user_data),
1130 unsigned long milliseconds, hidval user_data)
1132 GuiTimer *timer = g_new0 (GuiTimer, 1);
1133 hidval ret;
1135 timer->func = func;
1136 timer->user_data = user_data;
1137 timer->id = gtk_timeout_add (milliseconds, (GtkFunction) ghid_timer, timer);
1138 ret.ptr = (void *) timer;
1139 return ret;
1142 void
1143 ghid_stop_timer (hidval timer)
1145 void *ptr = timer.ptr;
1147 gtk_timeout_remove (((GuiTimer *) ptr)->id);
1148 g_free( ptr );
1151 typedef struct
1153 void (*func) ( hidval, int, unsigned int, hidval );
1154 hidval user_data;
1155 int fd;
1156 GIOChannel *channel;
1157 gint id;
1159 GuiWatch;
1161 /* We need a wrapper around the hid file watch to pass the correct flags
1163 static gboolean
1164 ghid_watch (GIOChannel *source, GIOCondition condition, gpointer data)
1166 unsigned int pcb_condition = 0;
1167 hidval x;
1168 GuiWatch *watch = (GuiWatch*)data;
1170 if (condition & G_IO_IN)
1171 pcb_condition |= PCB_WATCH_READABLE;
1172 if (condition & G_IO_OUT)
1173 pcb_condition |= PCB_WATCH_WRITABLE;
1174 if (condition & G_IO_ERR)
1175 pcb_condition |= PCB_WATCH_ERROR;
1176 if (condition & G_IO_HUP)
1177 pcb_condition |= PCB_WATCH_HANGUP;
1179 x.ptr = (void *) watch;
1180 watch->func (x, watch->fd, pcb_condition, watch->user_data);
1181 ghid_mode_cursor (Settings.Mode);
1183 return TRUE; /* Leave watch on */
1186 hidval
1187 ghid_watch_file (int fd, unsigned int condition, void (*func) (hidval watch, int fd, unsigned int condition, hidval user_data),
1188 hidval user_data)
1190 GuiWatch *watch = g_new0 (GuiWatch, 1);
1191 hidval ret;
1192 unsigned int glib_condition = 0;
1194 if (condition & PCB_WATCH_READABLE)
1195 glib_condition |= G_IO_IN;
1196 if (condition & PCB_WATCH_WRITABLE)
1197 glib_condition |= G_IO_OUT;
1198 if (condition & PCB_WATCH_ERROR)
1199 glib_condition |= G_IO_ERR;
1200 if (condition & PCB_WATCH_HANGUP)
1201 glib_condition |= G_IO_HUP;
1203 watch->func = func;
1204 watch->user_data = user_data;
1205 watch->fd = fd;
1206 watch->channel = g_io_channel_unix_new( fd );
1207 watch->id = g_io_add_watch( watch->channel, glib_condition, ghid_watch, watch );
1209 ret.ptr = (void *) watch;
1210 return ret;
1213 void
1214 ghid_unwatch_file (hidval data)
1216 GuiWatch *watch = (GuiWatch*)data.ptr;
1218 g_io_channel_shutdown( watch->channel, TRUE, NULL );
1219 g_io_channel_unref( watch->channel );
1220 g_free( watch );
1223 typedef struct
1225 GSource source;
1226 void (*func) (hidval user_data);
1227 hidval user_data;
1228 } BlockHookSource;
1230 static gboolean ghid_block_hook_prepare (GSource *source,
1231 gint *timeout);
1232 static gboolean ghid_block_hook_check (GSource *source);
1233 static gboolean ghid_block_hook_dispatch (GSource *source,
1234 GSourceFunc callback,
1235 gpointer user_data);
1237 static GSourceFuncs ghid_block_hook_funcs = {
1238 ghid_block_hook_prepare,
1239 ghid_block_hook_check,
1240 ghid_block_hook_dispatch,
1241 NULL // No destroy notification
1244 static gboolean
1245 ghid_block_hook_prepare (GSource *source,
1246 gint *timeout)
1248 hidval data = ((BlockHookSource *)source)->user_data;
1249 ((BlockHookSource *)source)->func( data );
1250 return FALSE;
1253 static gboolean
1254 ghid_block_hook_check (GSource *source)
1256 return FALSE;
1259 static gboolean
1260 ghid_block_hook_dispatch (GSource *source,
1261 GSourceFunc callback,
1262 gpointer user_data)
1264 return FALSE;
1267 static hidval
1268 ghid_add_block_hook (void (*func) (hidval data),
1269 hidval user_data)
1271 hidval ret;
1272 BlockHookSource *source;
1274 source = (BlockHookSource *)g_source_new (&ghid_block_hook_funcs, sizeof( BlockHookSource ));
1276 source->func = func;
1277 source->user_data = user_data;
1279 g_source_attach ((GSource *)source, NULL);
1281 ret.ptr = (void *) source;
1282 return ret;
1285 static void
1286 ghid_stop_block_hook (hidval mlpoll)
1288 GSource *source = (GSource *)mlpoll.ptr;
1289 g_source_destroy( source );
1293 ghid_confirm_dialog (char *msg, ...)
1295 int rv;
1297 /* FIXME -- deal with the ... part! */
1298 rv = ghid_dialog_confirm (msg);
1300 return rv;
1303 void
1304 ghid_report_dialog (char *title, char *msg)
1306 ghid_dialog_report (title, msg);
1309 char *
1310 ghid_prompt_for (char *msg, char *default_string)
1312 char *rv;
1314 rv = ghid_dialog_input (msg, default_string);
1315 return rv;
1319 ghid_attribute_dialog (HID_Attribute * attrs,
1320 int n_attrs, HID_Attr_Val * results)
1322 printf ("ghid_attribute_dialog() -- not implemented yet\n");
1323 return 0;
1326 void
1327 ghid_show_item (void *item)
1329 ghid_pinout_window_show (&ghid_port, (ElementTypePtr) item);
1332 void
1333 ghid_beep ()
1335 gdk_beep ();
1338 static int
1339 ghid_progress (int so_far, int total, const char *message)
1341 return 0;
1344 /* ---------------------------------------------------------------------- */
1346 HID ghid_hid = {
1347 sizeof (HID),
1348 "gtk",
1349 "Gtk - The Gimp Toolkit",
1350 1, /* gui */
1351 0, /* printer */
1352 0, /* exporter */
1353 0, /* poly before */
1354 1, /* poly after */
1355 0, /* poly dicer */
1357 ghid_get_export_options,
1358 ghid_do_export,
1359 ghid_parse_arguments,
1361 ghid_invalidate_wh,
1362 ghid_invalidate_lr,
1363 ghid_invalidate_all,
1364 ghid_set_layer,
1365 ghid_make_gc,
1366 ghid_destroy_gc,
1367 ghid_use_mask,
1368 ghid_set_color,
1369 ghid_set_line_cap,
1370 ghid_set_line_width,
1371 ghid_set_draw_xor,
1372 ghid_set_draw_faded,
1373 ghid_set_line_cap_angle,
1374 ghid_draw_line,
1375 ghid_draw_arc,
1376 ghid_draw_rect,
1377 ghid_fill_circle,
1378 ghid_fill_polygon,
1379 ghid_fill_rect,
1381 ghid_calibrate,
1382 ghid_shift_is_pressed,
1383 ghid_control_is_pressed,
1384 ghid_get_coords,
1385 ghid_set_crosshair,
1386 ghid_add_timer,
1387 ghid_stop_timer,
1388 ghid_watch_file,
1389 ghid_unwatch_file,
1390 ghid_add_block_hook,
1391 ghid_stop_block_hook,
1393 ghid_log,
1394 ghid_logv,
1395 ghid_confirm_dialog,
1396 ghid_report_dialog,
1397 ghid_prompt_for,
1398 ghid_attribute_dialog,
1399 ghid_show_item,
1400 ghid_beep,
1401 ghid_progress
1404 HID ghid_extents = {
1405 sizeof (HID),
1406 "ghid_extents",
1407 "used to calculate extents",
1408 1, /* gui */
1409 0, /* printer */
1410 0, /* exporter */
1411 0, /* poly before */
1412 1, /* poly after */
1413 0, /* poly dicer */
1415 0 /* ghid_get_export_options */ ,
1416 0 /* ghid_do_export */ ,
1417 0 /* ghid_parse_arguments */ ,
1419 0 /* ghid_invalidate_wh */ ,
1420 0 /* ghid_invalidate_lr */ ,
1421 0 /* ghid_invalidate_all */ ,
1422 0 /* ghid_set_layer */ ,
1423 0 /* ghid_make_gc */ ,
1424 0 /* ghid_destroy_gc */ ,
1425 ghid_extents_use_mask,
1426 0 /* ghid_set_color */ ,
1427 0 /* ghid_set_line_cap */ ,
1428 0 /* ghid_set_line_width */ ,
1429 0 /* ghid_set_draw_xor */ ,
1430 0 /* ghid_set_draw_faded */ ,
1431 0 /* ghid_set_line_cap_angle */ ,
1432 ghid_extents_draw_line,
1433 ghid_extents_draw_arc,
1434 ghid_extents_draw_rect,
1435 ghid_extents_fill_circle,
1436 ghid_extents_fill_polygon,
1437 ghid_extents_fill_rect,
1439 0 /* ghid_calibrate */ ,
1440 0 /* ghid_shift_is_pressed */ ,
1441 0 /* ghid_control_is_pressed */ ,
1442 0 /* ghid_get_coords */ ,
1443 0 /* ghid_set_crosshair */ ,
1444 0 /* ghid_add_timer */ ,
1445 0 /* ghid_stop_timer */ ,
1446 0 /* ghid_watch_file */ ,
1447 0 /* ghid_unwatch_file */ ,
1448 0 /* ghid_add_block_hook */ ,
1449 0 /* ghid_stop_block_hook */ ,
1451 0 /* ghid_log */ ,
1452 0 /* ghid_logv */ ,
1453 0 /* ghid_confirm_dialog */ ,
1454 0 /* ghid_report_dialog */ ,
1455 0 /* ghid_prompt_for */ ,
1456 0 /* ghid_attribute_dialog */ ,
1457 0 /* ghid_show_item */ ,
1458 0 /* ghid_beep */ ,
1459 0 /* ghid_progress */
1462 /* ------------------------------------------------------------
1464 * Actions specific to the GTK HID follow from here
1469 /* ------------------------------------------------------------ */
1470 static const char about_syntax[] =
1471 "About()";
1473 static const char about_help[] =
1474 "Tell the user about this version of PCB.";
1476 /* %start-doc actions About
1478 This just pops up a dialog telling the user which version of
1479 @code{pcb} they're running.
1481 %end-doc */
1484 static int
1485 About (int argc, char **argv, int x, int y)
1487 ghid_dialog_about ();
1488 return 0;
1491 /* ------------------------------------------------------------ */
1492 static const char getxy_syntax[] =
1493 "GetXY()";
1495 static const char getxy_help[] =
1496 "Get a coordinate.";
1498 /* %start-doc actions GetXY
1500 Prompts the user for a coordinate, if one is not already selected.
1502 %end-doc */
1504 static int
1505 GetXY (int argc, char **argv, int x, int y)
1507 return 0;
1510 /* ---------------------------------------------------------------------- */
1512 static int PointCursor (int argc, char **argv, int x, int y)
1514 if (!ghidgui)
1515 return 0;
1517 if (argc > 0)
1518 ghid_point_cursor ();
1519 else
1520 ghid_mode_cursor (Settings.Mode);
1521 return 0;
1524 /* ---------------------------------------------------------------------- */
1526 static int
1527 RouteStylesChanged (int argc, char **argv, int x, int y)
1529 gint n;
1531 if (PCB && PCB->RouteStyle[0].Name)
1532 for (n = 0; n < NUM_STYLES; ++n)
1533 ghid_route_style_set_button_label ((&PCB->RouteStyle[n])->Name, n);
1534 return 0;
1537 /* ---------------------------------------------------------------------- */
1540 PCBChanged (int argc, char **argv, int x, int y)
1542 if (!ghidgui)
1543 return 0;
1545 ghid_window_set_name_label (PCB->Name);
1547 if (!gport->pixmap)
1548 return 0;
1549 RouteStylesChanged (0, NULL, 0, 0);
1550 ghid_port_ranges_scale (TRUE);
1551 ghid_port_ranges_pan (0, 0, FALSE);
1552 ghid_port_ranges_zoom (0);
1553 ghid_port_ranges_changed ();
1554 ghid_sync_with_new_layout ();
1555 return 0;
1558 /* ---------------------------------------------------------------------- */
1560 static int
1561 LayerGroupsChanged (int argc, char **argv, int x, int y)
1563 printf ("LayerGroupsChanged -- not implemented\n");
1564 return 0;
1567 /* ---------------------------------------------------------------------- */
1569 static int
1570 LibraryChanged (int argc, char **argv, int x, int y)
1572 ghid_library_window_show (&ghid_port, FALSE);
1573 return 0;
1576 /* ---------------------------------------------------------------------- */
1578 static int
1579 Command (int argc, char **argv, int x, int y)
1581 ghid_handle_user_command (FALSE);
1582 return 0;
1585 /* ---------------------------------------------------------------------- */
1587 static int
1588 Load (int argc, char **argv, int x, int y)
1590 char *function;
1591 char *name = NULL;
1593 static gchar *current_element_dir = NULL;
1594 static gchar *current_layout_dir = NULL;
1595 static gchar *current_netlist_dir = NULL;
1597 /* we've been given the file name */
1598 if (argc > 1)
1599 return hid_actionv ("LoadFrom", argc, argv);
1601 function = argc ? argv[0] : "Layout";
1603 if (strcasecmp (function, "Netlist") == 0)
1605 name = ghid_dialog_file_select_open (_("Load netlist file"),
1606 &current_netlist_dir,
1607 Settings.FilePath);
1609 else if (strcasecmp (function, "ElementToBuffer") == 0)
1611 name = ghid_dialog_file_select_open (_("Load element to buffer"),
1612 &current_element_dir,
1613 Settings.LibraryTree);
1615 else if (strcasecmp (function, "LayoutToBuffer") == 0)
1617 name = ghid_dialog_file_select_open (_("Load layout file to buffer"),
1618 &current_layout_dir,
1619 Settings.FilePath);
1621 else if (strcasecmp (function, "Layout") == 0)
1623 name = ghid_dialog_file_select_open (_("Load layout file"),
1624 &current_layout_dir,
1625 Settings.FilePath);
1628 if (name)
1630 if (Settings.verbose)
1631 fprintf (stderr, "%s: Calling LoadFrom(%s, %s)\n", __FUNCTION__,
1632 function, name);
1633 hid_actionl ("LoadFrom", function, name, NULL);
1634 g_free (name);
1637 return 0;
1640 /* ---------------------------------------------------------------------- */
1642 static int
1643 LoadVendor (int argc, char **argv, int x, int y)
1645 char *name;
1646 static gchar *current_vendor_dir = NULL;
1648 if (argc > 0)
1649 return hid_actionv ("LoadVendorFrom", argc, argv);
1651 name = ghid_dialog_file_select_open (_("Load vendor file"),
1652 &current_vendor_dir,
1653 Settings.FilePath);
1655 if (name)
1657 if (Settings.verbose)
1658 fprintf (stderr, "%s: Calling LoadVendorFrom(%s)\n", __FUNCTION__,
1659 name);
1660 hid_actionl ("LoadVendorFrom", name, NULL);
1661 g_free (name);
1664 return 0;
1667 /* ---------------------------------------------------------------------- */
1669 static int
1670 Save (int argc, char **argv, int x, int y)
1672 char *function;
1673 char *name;
1674 static gchar *current_dir = NULL;
1676 if (argc > 1)
1677 return hid_actionv ("SaveTo", argc, argv);
1679 function = argc ? argv[0] : "Layout";
1681 if (strcasecmp (function, "Layout") == 0)
1682 if (PCB->Filename)
1683 return hid_actionl ("SaveTo", "Layout", PCB->Filename, NULL);
1685 name = ghid_dialog_file_select_save (_("Save layout as"),
1686 &current_dir,
1687 PCB->Filename, Settings.FilePath);
1689 if (name)
1691 FILE *exist;
1692 exist = fopen (name, "r");
1693 if (exist)
1695 fclose (exist);
1696 if (ghid_dialog_confirm (_("File exists! Ok to overwrite?")))
1698 if (Settings.verbose)
1699 fprintf (stderr, "Overwriting %s\n", name);
1701 else
1703 g_free (name);
1704 return 1;
1708 if (Settings.verbose)
1709 fprintf (stderr, "%s: Calling SaveTo(%s, %s)\n", __FUNCTION__, function,
1710 name);
1713 * if we got this far and the function is Layout, then
1714 * we really needed it to be a LayoutAs. Otherwise
1715 * ActionSaveTo() will ignore the new file name we
1716 * just obtained.
1718 if (strcasecmp (function, "Layout") == 0)
1719 hid_actionl ("SaveTo", "LayoutAs", name, NULL);
1720 else
1721 hid_actionl ("SaveTo", function, name, NULL);
1722 g_free (name);
1725 return 0;
1728 /* ---------------------------------------------------------------------- */
1729 static const char swapsides_syntax[] =
1730 "SwapSides(|v|h|r)";
1732 static const char swapsides_help[] =
1733 "Swaps the side of the board you're looking at.";
1735 /* %start-doc actions SwapSides
1737 This action changes the way you view the board.
1739 @table @code
1741 @item v
1742 Flips the board over vertically (up/down).
1744 @item h
1745 Flips the board over horizontally (left/right), like flipping pages in
1746 a book.
1748 @item r
1749 Rotates the board 180 degrees without changing sides.
1751 @end table
1753 If no argument is given, the board isn't moved but the opposite side
1754 is shown.
1756 Normally, this action changes which pads and silk layer are drawn as
1757 true silk, and which are drawn as the "invisible" layer. It also
1758 determines which solder mask you see.
1760 As a special case, if the layer group for the side you're looking at
1761 is visible and currently active, and the layer group for the opposite
1762 is not visible (i.e. disabled), then this action will also swap which
1763 layer group is visible and active, effectively swapping the ``working
1764 side'' of the board.
1766 %end-doc */
1769 static int
1770 SwapSides (int argc, char **argv, int x, int y)
1772 gint dx;
1773 int comp_group = GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER);
1774 int solder_group = GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER);
1775 int active_group = GetLayerGroupNumberByNumber (LayerStack[0]);
1776 int comp_showing =
1777 PCB->Data->Layer[PCB->LayerGroups.Entries[comp_group][0]].On;
1778 int solder_showing =
1779 PCB->Data->Layer[PCB->LayerGroups.Entries[solder_group][0]].On;
1782 if (argc > 0)
1784 switch (argv[0][0]) {
1785 case 'h':
1786 case 'H':
1787 ghid_flip_x = ! ghid_flip_x;
1788 break;
1789 case 'v':
1790 case 'V':
1791 ghid_flip_y = ! ghid_flip_y;
1792 break;
1793 case 'r':
1794 case 'R':
1795 ghid_flip_x = ! ghid_flip_x;
1796 ghid_flip_y = ! ghid_flip_y;
1797 break;
1798 default:
1799 return 1;
1801 /* SwapSides will swap this */
1802 Settings.ShowSolderSide = (ghid_flip_x == ghid_flip_y);
1805 Settings.ShowSolderSide = !Settings.ShowSolderSide;
1806 if (Settings.ShowSolderSide)
1808 if (active_group == comp_group && comp_showing && !solder_showing)
1810 ChangeGroupVisibility (PCB->LayerGroups.Entries[comp_group][0], 0,
1812 ChangeGroupVisibility (PCB->LayerGroups.Entries[solder_group][0], 1,
1816 else
1818 if (active_group == solder_group && solder_showing && !comp_showing)
1820 ChangeGroupVisibility (PCB->LayerGroups.Entries[solder_group][0], 0,
1822 ChangeGroupVisibility (PCB->LayerGroups.Entries[comp_group][0], 1,
1827 /* what does this do? */
1828 dx = PCB->MaxWidth / 2 - gport->view_x;
1829 ghid_port_ranges_pan (2 * dx, 0, TRUE);
1831 ghid_invalidate_all ();
1832 return 0;
1835 static int
1836 Print (int argc, char **argv, int x, int y)
1838 HID **hids;
1839 int i;
1840 HID *printer = NULL;
1842 hids = hid_enumerate ();
1843 for (i = 0; hids[i]; i++)
1845 if (hids[i]->printer)
1846 printer = hids[i];
1849 if (printer == NULL)
1851 gui->log (_("Can't find a suitable printer HID"));
1852 return -1;
1855 /* check if layout is empty */
1856 if (!IsDataEmpty (PCB->Data))
1858 ghid_dialog_print (printer);
1860 else
1861 gui->log (_("Can't print empty layout"));
1863 return 0;
1866 static int
1867 Export (int argc, char **argv, int x, int y)
1870 /* check if layout is empty */
1871 if (!IsDataEmpty (PCB->Data))
1873 ghid_dialog_export ();
1875 else
1876 gui->log (_("Can't export empty layout"));
1878 return 0;
1881 static int
1882 Benchmark (int argc, char **argv, int x, int y)
1884 int i = 0;
1885 time_t start, end;
1886 BoxType region;
1887 GdkDisplay *display;
1889 display = gdk_drawable_get_display (gport->drawable);
1891 region.X1 = 0;
1892 region.Y1 = 0;
1893 region.X2 = PCB->MaxWidth;
1894 region.Y2 = PCB->MaxHeight;
1896 gdk_display_sync (display);
1897 time (&start);
1900 hid_expose_callback (&ghid_hid, &region, 0);
1901 gdk_display_sync (display);
1902 time (&end);
1903 i++;
1905 while (end - start < 10);
1907 printf ("%g redraws per second\n", i / 10.0);
1909 return 0;
1912 /* ------------------------------------------------------------ */
1914 static const char center_syntax[] =
1915 "Center()\n";
1917 static const char center_help[] =
1918 "Moves the pointer to the center of the window.";
1920 /* %start-doc actions Center
1922 Move the pointer to the center of the window, but only if it's
1923 currently within the window already.
1925 %end-doc */
1927 static int
1928 Center(int argc, char **argv, int x, int y)
1930 int x0, y0, w2, h2, dx, dy;
1932 if (argc != 0)
1933 AFAIL (center);
1935 x = GRIDFIT_X (SIDE_X (x), PCB->Grid);
1936 y = GRIDFIT_Y (SIDE_Y (y), PCB->Grid);
1938 w2 = gport->view_width / 2;
1939 h2 = gport->view_height / 2;
1940 x0 = x - w2;
1941 y0 = y - h2;
1943 if (x0 < 0)
1945 x0 = 0;
1946 x = x0 + w2;
1949 if (y0 < 0)
1951 y0 = 0;
1952 y = y0 + w2;
1955 dx = (x0 - gport->view_x0) / gport->zoom ;
1956 dy = (y0 - gport->view_y0) / gport->zoom;
1957 gport->view_x0 = x0;
1958 gport->view_y0 = y0;
1961 /* FIXME -- do I need something like the pan_fixup here? */
1962 /* lesstif_pan_fixup (); */
1964 /* Move the pointer to the center of the window, but only if it's
1965 currently within the window already. Watch out for edges,
1966 though. */
1968 #if GTK_CHECK_VERSION(2,8,0)
1970 GdkDisplay *display;
1971 GdkScreen *screen;
1972 gint cx, cy;
1974 display = gdk_display_get_default ();
1975 screen = gdk_display_get_default_screen (display);
1977 /* figure out where the pointer is and then move it from there by the specified delta */
1978 gdk_display_get_pointer (display, NULL, &cx, &cy, NULL);
1979 gdk_display_warp_pointer (display, screen, cx - dx, cy - dy);
1982 * Note that under X11, gdk_display_warp_pointer is just a wrapper around XWarpPointer, but
1983 * hopefully by avoiding the direct call to an X function we might still work under windows
1984 * and other non-X11 based gdk's
1987 #else
1988 # ifdef HAVE_GDK_GDKX_H
1991 Window w_src, w_dst;
1992 w_src = GDK_WINDOW_XID (gport->drawing_area->window);
1993 w_dst = w_src;
1995 /* don't warp with the auto drc - that creates auto-scroll chaos */
1996 if (TEST_FLAG (AUTODRCFLAG, PCB) && Settings.Mode == LINE_MODE
1997 && Crosshair.AttachedLine.State != STATE_FIRST)
1998 return 0;
2000 XWarpPointer (GDK_DRAWABLE_XDISPLAY (gport->drawing_area->window),
2001 w_src, w_dst,
2002 0, 0, 0, 0,
2003 Vx2 (x), Vy2 (y));
2005 /* XWarpPointer creates Motion events normally bound to
2006 * EventMoveCrosshair.
2007 * We don't do any updates when EventMoveCrosshair
2008 * is called the next time to prevent from rounding errors
2010 /* FIXME?
2011 * IgnoreMotionEvents = ignore;
2014 # endif
2015 #endif
2017 return 0;
2019 /* ------------------------------------------------------------ */
2021 static const char dowindows_syntax[] =
2022 "DoWindows(1|2|3|4)\n"
2023 "DoWindows(Layout|Library|Log|Netlist|Preferences)";
2025 static const char dowindows_help[] =
2026 "Open various GUI windows.";
2028 /* %start-doc actions DoWindows
2030 @table @code
2032 @item 1
2033 @itemx Layout
2034 Open the layout window. Since the layout window is always shown
2035 anyway, this has no effect.
2037 @item 2
2038 @itemx Library
2039 Open the library window.
2041 @item 3
2042 @itemx Log
2043 Open the log window.
2045 @item 4
2046 @itemx Netlist
2047 Open the netlist window.
2049 @item 5
2050 @itemx Preferences
2051 Open the preferences window.
2053 @end table
2055 %end-doc */
2057 static int
2058 DoWindows (int argc, char **argv, int x, int y)
2060 char *a = argc == 1 ? argv[0] : "";
2062 if (strcmp (a, "1") == 0 || strcasecmp (a, "Layout") == 0)
2065 else if (strcmp (a, "2") == 0 || strcasecmp (a, "Library") == 0)
2067 ghid_library_window_show (gport, TRUE);
2069 else if (strcmp (a, "3") == 0 || strcasecmp (a, "Log") == 0)
2071 ghid_log_window_show (TRUE);
2073 else if (strcmp (a, "4") == 0 || strcasecmp (a, "Netlist") == 0)
2075 ghid_netlist_window_show (gport, TRUE);
2077 else if (strcmp (a, "5") == 0 || strcasecmp (a, "Preferences") == 0)
2079 ghid_config_window_show ();
2081 else
2083 AFAIL (dowindows);
2086 return 0;
2089 /* ------------------------------------------------------------ */
2090 static const char setunits_syntax[] =
2091 "SetUnits(mm|mil)";
2093 static const char setunits_help[] =
2094 "Set the default measurement units.";
2096 /* %start-doc actions SetUnits
2098 @table @code
2100 @item mil
2101 Sets the display units to mils (1/1000 inch).
2103 @item mm
2104 Sets the display units to millimeters.
2106 @end table
2108 %end-doc */
2110 static int
2111 SetUnits (int argc, char **argv, int x, int y)
2113 if (argc == 0)
2114 return 0;
2115 if (strcmp (argv[0], "mil") == 0)
2116 Settings.grid_units_mm = 0;
2117 if (strcmp (argv[0], "mm") == 0)
2118 Settings.grid_units_mm = 1;
2120 ghid_config_handle_units_changed ();
2122 ghid_set_status_line_label ();
2124 /* FIXME ?
2125 * lesstif_sizes_reset ();
2126 * lesstif_styles_update_values ();
2128 return 0;
2131 /* ------------------------------------------------------------ */
2132 static const char popup_syntax[] =
2133 "Popup(MenuName, [Button])";
2135 static const char popup_help[] =
2136 "Bring up the popup menu specified by @code{MenuName}.\n"
2137 "If called by a mouse event then the mouse button number\n"
2138 "must be specified as the optional second argument.";
2140 /* %start-doc actions Popup
2142 This just pops up the specified menu. The menu must have been defined
2143 as a named subresource of the Popups resource in the menu resource
2144 file. If called as a response to a mouse button click, the mouse
2145 button number must be specified as the second argument.
2147 %end-doc */
2150 static int
2151 Popup (int argc, char **argv, int x, int y)
2153 GtkWidget *menu;
2154 char *element;
2155 guint button;
2157 if (argc != 1 && argc != 2)
2158 AFAIL (popup);
2160 if (argc == 1)
2161 button = 0;
2162 else
2163 button = atoi (argv[1]);
2165 if ( (element = (char *) malloc ( (strlen (argv[0]) + 2) * sizeof (char))) == NULL )
2167 fprintf (stderr, "Popup(): malloc failed\n");
2168 exit (1);
2171 sprintf (element, "/%s", argv[0]);
2172 printf ("Loading popup \"%s\". Button = %u\n", element, button);
2174 menu = gtk_ui_manager_get_widget (ghidgui->ui_manager, element);
2175 free (element);
2177 if (! GTK_IS_MENU (menu))
2179 Message ("The specified popup menu \"%s\" has not been defined.\n", argv[0]);
2180 return 1;
2182 else
2184 ghidgui->in_popup = TRUE;
2185 gtk_widget_grab_focus (ghid_port.drawing_area);
2186 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0,
2187 gtk_get_current_event_time());
2189 return 0;
2192 static int
2193 Busy (int argc, char **argv, int x, int y)
2195 ghid_watch_cursor ();
2196 return 0;
2199 HID_Action ghid_main_action_list[] = {
2200 {"About", 0, About, about_help, about_syntax},
2201 {"Benchmark", 0, Benchmark},
2202 {"Busy", 0, Busy},
2203 {"Center", "Click on a location to center", Center, center_help, center_syntax},
2204 {"Command", 0, Command},
2205 {"DoWindows", 0, DoWindows, dowindows_help, dowindows_syntax},
2206 {"Export", 0, Export},
2207 {"GetXY", "", GetXY, getxy_help, getxy_syntax},
2208 {"LayerGroupsChanged", 0, LayerGroupsChanged},
2209 {"LibraryChanged", 0, LibraryChanged},
2210 {"Load", 0, Load},
2211 {"LoadVendor", 0, LoadVendor},
2212 {"PCBChanged", 0, PCBChanged},
2213 {"PointCursor", 0, PointCursor},
2214 {"Popup", 0, Popup, popup_help, popup_syntax},
2215 {"Print", 0, Print},
2216 {"RouteStylesChanged", 0, RouteStylesChanged},
2217 {"Save", 0, Save},
2218 {"SetUnits", 0, SetUnits, setunits_help, setunits_syntax},
2219 {"SwapSides", 0, SwapSides, swapsides_help, swapsides_syntax},
2220 {"Zoom", "Click on zoom focus", Zoom, zoom_help, zoom_syntax}
2223 REGISTER_ACTIONS (ghid_main_action_list)
2226 static int
2227 flag_flipx (int x)
2229 return ghid_flip_x;
2231 static int
2232 flag_flipy (int x)
2234 return ghid_flip_y;
2237 HID_Flag ghid_main_flag_list[] = {
2238 {"flip_x", flag_flipx, 0},
2239 {"flip_y", flag_flipy, 0}
2242 REGISTER_FLAGS (ghid_main_flag_list)
2244 #include "dolists.h"
2247 * We will need these for finding the windows installation
2248 * directory. Without that we can't find our fonts and
2249 * footprint libraries.
2251 #ifdef WIN32
2252 #include <windows.h>
2253 #include <winreg.h>
2254 #endif
2256 void
2257 hid_gtk_init ()
2259 #ifdef WIN32
2261 char * tmps;
2262 char * share_dir;
2264 tmps = g_win32_get_package_installation_directory (PACKAGE "-" VERSION, NULL);
2265 #define REST_OF_PATH G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S PACKAGE
2266 share_dir = (char *) malloc(strlen(tmps) +
2267 strlen(REST_OF_PATH) +
2269 sprintf (share_dir, "%s%s", tmps, REST_OF_PATH);
2270 free (tmps);
2271 #undef REST_OF_PATH
2272 printf ("\"Share\" installation path is \"%s\"\n", share_dir);
2273 #endif
2275 hid_register_hid (&ghid_hid);
2276 apply_default_hid (&ghid_extents, &ghid_hid);
2277 #include "gtk_lists.h"