11 #include "hid/common/draw_helpers.h"
13 #ifdef HAVE_LIBDMALLOC
19 /* Sets priv->u_gc to the "right" GC to use (wrt mask or window)
21 #define USE_GC(gc) if (!use_gc(gc)) return
23 static enum mask_mode cur_mask
= HID_MASK_OFF
;
24 static int mask_seq
= 0;
26 typedef struct render_priv
{
33 GdkRectangle clip_rect
;
34 int attached_invalidate_depth
;
35 int mark_invalidate_depth
;
37 /* Feature for leading the user to a particular location */
38 guint lead_user_timeout
;
39 GTimer
*lead_user_timer
;
41 Coord lead_user_radius
;
49 typedef struct hid_gc_struct
63 static void draw_lead_user (render_priv
*priv
);
67 ghid_set_layer (const char *name
, int group
, int empty
)
70 if (idx
>= 0 && idx
< max_group
)
72 int n
= PCB
->LayerGroups
.Number
[group
];
73 for (idx
= 0; idx
< n
-1; idx
++)
75 int ni
= PCB
->LayerGroups
.Entries
[group
][idx
];
76 if (ni
>= 0 && ni
< max_copper_layer
+ 2
77 && PCB
->Data
->Layer
[ni
].On
)
80 idx
= PCB
->LayerGroups
.Entries
[group
][idx
];
83 if (idx
>= 0 && idx
< max_copper_layer
+ 2)
84 return /*pinout ? 1 : */ PCB
->Data
->Layer
[idx
].On
;
87 switch (SL_TYPE (idx
))
90 return /* pinout ? 0 : */ PCB
->InvisibleObjectsOn
;
92 if (SL_MYSIDE (idx
) /*&& !pinout */ )
93 return TEST_FLAG (SHOWMASKFLAG
, PCB
);
96 if (SL_MYSIDE (idx
) /*|| pinout */ )
97 return PCB
->ElementOn
;
112 ghid_destroy_gc (hidGC gc
)
115 g_object_unref (gc
->gc
);
124 rv
= g_new0 (hid_gc_struct
, 1);
125 rv
->me_pointer
= &ghid_hid
;
126 rv
->colorname
= Settings
.BackgroundColor
;
131 set_clip (render_priv
*priv
, GdkGC
*gc
)
137 gdk_gc_set_clip_rectangle (gc
, &priv
->clip_rect
);
139 gdk_gc_set_clip_mask (gc
, NULL
);
143 ghid_draw_grid (void)
145 static GdkPoint
*points
= 0;
146 static int npoints
= 0;
147 Coord x1
, y1
, x2
, y2
, x
, y
;
149 render_priv
*priv
= gport
->render_priv
;
151 if (!Settings
.DrawGrid
)
153 if (Vz (PCB
->Grid
) < MIN_GRID_DISTANCE
)
157 if (gdk_color_parse (Settings
.GridColor
, &gport
->grid_color
))
159 gport
->grid_color
.red
^= gport
->bg_color
.red
;
160 gport
->grid_color
.green
^= gport
->bg_color
.green
;
161 gport
->grid_color
.blue
^= gport
->bg_color
.blue
;
162 gdk_color_alloc (gport
->colormap
, &gport
->grid_color
);
164 priv
->grid_gc
= gdk_gc_new (gport
->drawable
);
165 gdk_gc_set_function (priv
->grid_gc
, GDK_XOR
);
166 gdk_gc_set_foreground (priv
->grid_gc
, &gport
->grid_color
);
167 gdk_gc_set_clip_origin (priv
->grid_gc
, 0, 0);
168 set_clip (priv
, priv
->grid_gc
);
170 x1
= GridFit (SIDE_X (gport
->view
.x0
), PCB
->Grid
, PCB
->GridOffsetX
);
171 y1
= GridFit (SIDE_Y (gport
->view
.y0
), PCB
->Grid
, PCB
->GridOffsetY
);
172 x2
= GridFit (SIDE_X (gport
->view
.x0
+ gport
->view
.width
- 1),
173 PCB
->Grid
, PCB
->GridOffsetX
);
174 y2
= GridFit (SIDE_Y (gport
->view
.y0
+ gport
->view
.height
- 1),
175 PCB
->Grid
, PCB
->GridOffsetY
);
192 if (Vx (x2
) >= gport
->width
)
194 if (Vy (y2
) >= gport
->height
)
196 n
= (x2
- x1
) / PCB
->Grid
+ 1;
200 points
= (GdkPoint
*)realloc (points
, npoints
* sizeof (GdkPoint
));
203 for (x
= x1
; x
<= x2
; x
+= PCB
->Grid
)
205 points
[n
].x
= Vx (x
);
210 for (y
= y1
; y
<= y2
; y
+= PCB
->Grid
)
212 for (i
= 0; i
< n
; i
++)
213 points
[i
].y
= Vy (y
);
214 gdk_draw_points (gport
->drawable
, priv
->grid_gc
, points
, n
);
218 /* ------------------------------------------------------------ */
220 ghid_draw_bg_image (void)
222 static GdkPixbuf
*pixbuf
;
223 GdkInterpType interp_type
;
224 gint x
, y
, w
, h
, w_src
, h_src
;
225 static gint w_scaled
, h_scaled
;
226 render_priv
*priv
= gport
->render_priv
;
228 if (!ghidgui
->bg_pixbuf
)
231 w
= PCB
->MaxWidth
/ gport
->view
.coord_per_px
;
232 h
= PCB
->MaxHeight
/ gport
->view
.coord_per_px
;
233 x
= gport
->view
.x0
/ gport
->view
.coord_per_px
;
234 y
= gport
->view
.y0
/ gport
->view
.coord_per_px
;
236 if (w_scaled
!= w
|| h_scaled
!= h
)
239 g_object_unref (G_OBJECT (pixbuf
));
241 w_src
= gdk_pixbuf_get_width (ghidgui
->bg_pixbuf
);
242 h_src
= gdk_pixbuf_get_height (ghidgui
->bg_pixbuf
);
243 if (w
> w_src
&& h
> h_src
)
244 interp_type
= GDK_INTERP_NEAREST
;
246 interp_type
= GDK_INTERP_BILINEAR
;
249 gdk_pixbuf_scale_simple (ghidgui
->bg_pixbuf
, w
, h
, interp_type
);
254 gdk_pixbuf_render_to_drawable (pixbuf
, gport
->drawable
, priv
->bg_gc
,
256 w
- x
, h
- y
, GDK_RGB_DITHER_NORMAL
, 0, 0);
259 #define WHICH_GC(gc) (cur_mask == HID_MASK_CLEAR ? priv->mask_gc : (gc)->gc)
262 ghid_use_mask (enum mask_mode mode
)
264 static int mask_seq_id
= 0;
266 render_priv
*priv
= gport
->render_priv
;
270 if (mode
== cur_mask
)
275 gport
->drawable
= gport
->pixmap
;
279 case HID_MASK_BEFORE
:
280 /* The HID asks not to receive this mask type, so warn if we get it */
281 g_return_if_reached ();
285 gport
->mask
= gdk_pixmap_new (0, gport
->width
, gport
->height
, 1);
286 gport
->drawable
= gport
->mask
;
290 priv
->mask_gc
= gdk_gc_new (gport
->drawable
);
291 gdk_gc_set_clip_origin (priv
->mask_gc
, 0, 0);
292 set_clip (priv
, priv
->mask_gc
);
295 gdk_gc_set_foreground (priv
->mask_gc
, &color
);
296 gdk_draw_rectangle (gport
->drawable
, priv
->mask_gc
, TRUE
, 0, 0,
297 gport
->width
, gport
->height
);
299 gdk_gc_set_foreground (priv
->mask_gc
, &color
);
306 mask_seq
= mask_seq_id
;
308 gport
->drawable
= gport
->pixmap
;
325 /* Config helper functions for when the user changes color preferences.
326 | set_special colors used in the gtkhid.
329 set_special_grid_color (void)
331 render_priv
*priv
= gport
->render_priv
;
333 if (!gport
->colormap
)
335 gport
->grid_color
.red
^= gport
->bg_color
.red
;
336 gport
->grid_color
.green
^= gport
->bg_color
.green
;
337 gport
->grid_color
.blue
^= gport
->bg_color
.blue
;
338 gdk_color_alloc (gport
->colormap
, &gport
->grid_color
);
340 gdk_gc_set_foreground (priv
->grid_gc
, &gport
->grid_color
);
344 ghid_set_special_colors (HID_Attribute
* ha
)
346 render_priv
*priv
= gport
->render_priv
;
348 if (!ha
->name
|| !ha
->value
)
350 if (!strcmp (ha
->name
, "background-color") && priv
->bg_gc
)
352 ghid_map_color_string (*(char **) ha
->value
, &gport
->bg_color
);
353 gdk_gc_set_foreground (priv
->bg_gc
, &gport
->bg_color
);
354 set_special_grid_color ();
356 else if (!strcmp (ha
->name
, "off-limit-color") && priv
->offlimits_gc
)
358 ghid_map_color_string (*(char **) ha
->value
, &gport
->offlimits_color
);
359 gdk_gc_set_foreground (priv
->offlimits_gc
, &gport
->offlimits_color
);
361 else if (!strcmp (ha
->name
, "grid-color") && priv
->grid_gc
)
363 ghid_map_color_string (*(char **) ha
->value
, &gport
->grid_color
);
364 set_special_grid_color ();
369 ghid_set_color (hidGC gc
, const char *name
)
371 static void *cache
= 0;
376 fprintf (stderr
, "%s(): name = NULL, setting to magenta\n",
381 gc
->colorname
= (char *) name
;
384 if (gport
->colormap
== 0)
385 gport
->colormap
= gtk_widget_get_colormap (gport
->top_window
);
387 if (strcmp (name
, "erase") == 0)
389 gdk_gc_set_foreground (gc
->gc
, &gport
->bg_color
);
391 else if (strcmp (name
, "drill") == 0)
393 gdk_gc_set_foreground (gc
->gc
, &gport
->offlimits_color
);
398 if (hid_cache_color (0, name
, &cval
, &cache
))
399 cc
= (ColorCache
*) cval
.ptr
;
402 cc
= (ColorCache
*) malloc (sizeof (ColorCache
));
403 memset (cc
, 0, sizeof (*cc
));
405 hid_cache_color (1, name
, &cval
, &cache
);
410 if (gdk_color_parse (name
, &cc
->color
))
411 gdk_color_alloc (gport
->colormap
, &cc
->color
);
413 gdk_color_white (gport
->colormap
, &cc
->color
);
420 cc
->xor_color
.red
= cc
->color
.red
^ gport
->bg_color
.red
;
421 cc
->xor_color
.green
= cc
->color
.green
^ gport
->bg_color
.green
;
422 cc
->xor_color
.blue
= cc
->color
.blue
^ gport
->bg_color
.blue
;
423 gdk_color_alloc (gport
->colormap
, &cc
->xor_color
);
426 gdk_gc_set_foreground (gc
->gc
, &cc
->xor_color
);
430 gdk_gc_set_foreground (gc
->gc
, &cc
->color
);
436 ghid_set_line_cap (hidGC gc
, EndCapStyle style
)
438 render_priv
*priv
= gport
->render_priv
;
444 gc
->cap
= GDK_CAP_ROUND
;
445 gc
->join
= GDK_JOIN_ROUND
;
449 gc
->cap
= GDK_CAP_PROJECTING
;
450 gc
->join
= GDK_JOIN_MITER
;
454 gdk_gc_set_line_attributes (WHICH_GC (gc
),
455 Vz (gc
->width
), GDK_LINE_SOLID
,
456 (GdkCapStyle
)gc
->cap
, (GdkJoinStyle
)gc
->join
);
460 ghid_set_line_width (hidGC gc
, Coord width
)
462 render_priv
*priv
= gport
->render_priv
;
466 gdk_gc_set_line_attributes (WHICH_GC (gc
),
467 Vz (gc
->width
), GDK_LINE_SOLID
,
468 (GdkCapStyle
)gc
->cap
, (GdkJoinStyle
)gc
->join
);
472 ghid_set_draw_xor (hidGC gc
, int xor_mask
)
474 gc
->xor_mask
= xor_mask
;
477 gdk_gc_set_function (gc
->gc
, xor_mask
? GDK_XOR
: GDK_COPY
);
478 ghid_set_color (gc
, gc
->colorname
);
484 render_priv
*priv
= gport
->render_priv
;
485 GdkWindow
*window
= gtk_widget_get_window (gport
->top_window
);
487 if (gc
->me_pointer
!= &ghid_hid
)
489 fprintf (stderr
, "Fatal: GC from another HID passed to GTK HID\n");
497 gc
->gc
= gdk_gc_new (window
);
498 ghid_set_color (gc
, gc
->colorname
);
499 ghid_set_line_width (gc
, gc
->width
);
500 ghid_set_line_cap (gc
, (EndCapStyle
)gc
->cap
);
501 ghid_set_draw_xor (gc
, gc
->xor_mask
);
502 gdk_gc_set_clip_origin (gc
->gc
, 0, 0);
504 if (gc
->mask_seq
!= mask_seq
)
507 gdk_gc_set_clip_mask (gc
->gc
, gport
->mask
);
509 set_clip (priv
, gc
->gc
);
510 gc
->mask_seq
= mask_seq
;
512 priv
->u_gc
= WHICH_GC (gc
);
517 ghid_draw_line (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
519 double dx1
, dy1
, dx2
, dy2
;
520 render_priv
*priv
= gport
->render_priv
;
522 dx1
= Vx ((double) x1
);
523 dy1
= Vy ((double) y1
);
524 dx2
= Vx ((double) x2
);
525 dy2
= Vy ((double) y2
);
527 if (!ClipLine (0, 0, gport
->width
, gport
->height
,
528 &dx1
, &dy1
, &dx2
, &dy2
, gc
->width
/ gport
->view
.coord_per_px
))
532 gdk_draw_line (gport
->drawable
, priv
->u_gc
, dx1
, dy1
, dx2
, dy2
);
536 ghid_draw_arc (hidGC gc
, Coord cx
, Coord cy
,
537 Coord xradius
, Coord yradius
, Angle start_angle
, Angle delta_angle
)
541 render_priv
*priv
= gport
->render_priv
;
543 w
= gport
->width
* gport
->view
.coord_per_px
;
544 h
= gport
->height
* gport
->view
.coord_per_px
;
545 radius
= (xradius
> yradius
) ? xradius
: yradius
;
546 if (SIDE_X (cx
) < gport
->view
.x0
- radius
547 || SIDE_X (cx
) > gport
->view
.x0
+ w
+ radius
548 || SIDE_Y (cy
) < gport
->view
.y0
- radius
549 || SIDE_Y (cy
) > gport
->view
.y0
+ h
+ radius
)
556 if (gport
->view
.flip_x
)
558 start_angle
= 180 - start_angle
;
559 delta_angle
= -delta_angle
;
561 if (gport
->view
.flip_y
)
563 start_angle
= -start_angle
;
564 delta_angle
= -delta_angle
;
566 /* make sure we fall in the -180 to +180 range */
567 start_angle
= NormalizeAngle (start_angle
);
568 if (start_angle
>= 180) start_angle
-= 360;
570 gdk_draw_arc (gport
->drawable
, priv
->u_gc
, 0,
571 Vx (cx
) - vrx
, Vy (cy
) - vry
,
572 vrx
* 2, vry
* 2, (start_angle
+ 180) * 64, delta_angle
* 64);
576 ghid_draw_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
579 render_priv
*priv
= gport
->render_priv
;
582 w
= gport
->width
* gport
->view
.coord_per_px
;
583 h
= gport
->height
* gport
->view
.coord_per_px
;
585 if ((SIDE_X (x1
) < gport
->view
.x0
- lw
586 && SIDE_X (x2
) < gport
->view
.x0
- lw
)
587 || (SIDE_X (x1
) > gport
->view
.x0
+ w
+ lw
588 && SIDE_X (x2
) > gport
->view
.x0
+ w
+ lw
)
589 || (SIDE_Y (y1
) < gport
->view
.y0
- lw
590 && SIDE_Y (y2
) < gport
->view
.y0
- lw
)
591 || (SIDE_Y (y1
) > gport
->view
.y0
+ h
+ lw
592 && SIDE_Y (y2
) > gport
->view
.y0
+ h
+ lw
))
614 gdk_draw_rectangle (gport
->drawable
, priv
->u_gc
, FALSE
,
615 x1
, y1
, x2
- x1
+ 1, y2
- y1
+ 1);
620 ghid_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
)
623 render_priv
*priv
= gport
->render_priv
;
625 w
= gport
->width
* gport
->view
.coord_per_px
;
626 h
= gport
->height
* gport
->view
.coord_per_px
;
627 if (SIDE_X (cx
) < gport
->view
.x0
- radius
628 || SIDE_X (cx
) > gport
->view
.x0
+ w
+ radius
629 || SIDE_Y (cy
) < gport
->view
.y0
- radius
630 || SIDE_Y (cy
) > gport
->view
.y0
+ h
+ radius
)
635 gdk_draw_arc (gport
->drawable
, priv
->u_gc
, TRUE
,
636 Vx (cx
) - vr
, Vy (cy
) - vr
, vr
* 2, vr
* 2, 0, 360 * 64);
640 ghid_fill_polygon (hidGC gc
, int n_coords
, Coord
*x
, Coord
*y
)
642 static GdkPoint
*points
= 0;
643 static int npoints
= 0;
645 render_priv
*priv
= gport
->render_priv
;
648 if (npoints
< n_coords
)
650 npoints
= n_coords
+ 1;
651 points
= (GdkPoint
*)realloc (points
, npoints
* sizeof (GdkPoint
));
653 for (i
= 0; i
< n_coords
; i
++)
655 points
[i
].x
= Vx (x
[i
]);
656 points
[i
].y
= Vy (y
[i
]);
658 gdk_draw_polygon (gport
->drawable
, priv
->u_gc
, 1, points
, n_coords
);
662 ghid_fill_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
664 gint w
, h
, lw
, xx
, yy
;
665 render_priv
*priv
= gport
->render_priv
;
668 w
= gport
->width
* gport
->view
.coord_per_px
;
669 h
= gport
->height
* gport
->view
.coord_per_px
;
671 if ((SIDE_X (x1
) < gport
->view
.x0
- lw
672 && SIDE_X (x2
) < gport
->view
.x0
- lw
)
673 || (SIDE_X (x1
) > gport
->view
.x0
+ w
+ lw
674 && SIDE_X (x2
) > gport
->view
.x0
+ w
+ lw
)
675 || (SIDE_Y (y1
) < gport
->view
.y0
- lw
676 && SIDE_Y (y2
) < gport
->view
.y0
- lw
)
677 || (SIDE_Y (y1
) > gport
->view
.y0
+ h
+ lw
678 && SIDE_Y (y2
) > gport
->view
.y0
+ h
+ lw
))
698 gdk_draw_rectangle (gport
->drawable
, priv
->u_gc
, TRUE
,
699 x1
, y1
, x2
- x1
+ 1, y2
- y1
+ 1);
703 redraw_region (GdkRectangle
*rect
)
705 int eleft
, eright
, etop
, ebottom
;
707 render_priv
*priv
= gport
->render_priv
;
714 priv
->clip_rect
= *rect
;
719 priv
->clip_rect
.x
= 0;
720 priv
->clip_rect
.y
= 0;
721 priv
->clip_rect
.width
= gport
->width
;
722 priv
->clip_rect
.height
= gport
->height
;
726 set_clip (priv
, priv
->bg_gc
);
727 set_clip (priv
, priv
->offlimits_gc
);
728 set_clip (priv
, priv
->mask_gc
);
729 set_clip (priv
, priv
->grid_gc
);
731 region
.X1
= MIN(Px(priv
->clip_rect
.x
),
732 Px(priv
->clip_rect
.x
+ priv
->clip_rect
.width
+ 1));
733 region
.Y1
= MIN(Py(priv
->clip_rect
.y
),
734 Py(priv
->clip_rect
.y
+ priv
->clip_rect
.height
+ 1));
735 region
.X2
= MAX(Px(priv
->clip_rect
.x
),
736 Px(priv
->clip_rect
.x
+ priv
->clip_rect
.width
+ 1));
737 region
.Y2
= MAX(Py(priv
->clip_rect
.y
),
738 Py(priv
->clip_rect
.y
+ priv
->clip_rect
.height
+ 1));
740 region
.X1
= MAX (0, MIN (PCB
->MaxWidth
, region
.X1
));
741 region
.X2
= MAX (0, MIN (PCB
->MaxWidth
, region
.X2
));
742 region
.Y1
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y1
));
743 region
.Y2
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y2
));
746 eright
= Vx (PCB
->MaxWidth
);
748 ebottom
= Vy (PCB
->MaxHeight
);
763 gdk_draw_rectangle (gport
->drawable
, priv
->offlimits_gc
,
764 1, 0, 0, eleft
, gport
->height
);
767 if (eright
< gport
->width
)
768 gdk_draw_rectangle (gport
->drawable
, priv
->offlimits_gc
,
769 1, eright
, 0, gport
->width
- eright
, gport
->height
);
771 eright
= gport
->width
;
773 gdk_draw_rectangle (gport
->drawable
, priv
->offlimits_gc
,
774 1, eleft
, 0, eright
- eleft
+ 1, etop
);
777 if (ebottom
< gport
->height
)
778 gdk_draw_rectangle (gport
->drawable
, priv
->offlimits_gc
,
779 1, eleft
, ebottom
, eright
- eleft
+ 1,
780 gport
->height
- ebottom
);
782 ebottom
= gport
->height
;
784 gdk_draw_rectangle (gport
->drawable
, priv
->bg_gc
, 1,
785 eleft
, etop
, eright
- eleft
+ 1, ebottom
- etop
+ 1);
787 ghid_draw_bg_image();
789 hid_expose_callback (&ghid_hid
, ®ion
, 0);
792 /* In some cases we are called with the crosshair still off */
793 if (priv
->attached_invalidate_depth
== 0)
794 DrawAttached (priv
->crosshair_gc
);
796 /* In some cases we are called with the mark still off */
797 if (priv
->mark_invalidate_depth
== 0)
798 DrawMark (priv
->crosshair_gc
);
800 draw_lead_user (priv
);
804 /* Rest the clip for bg_gc, as it is used outside this function */
805 gdk_gc_set_clip_mask (priv
->bg_gc
, NULL
);
809 ghid_invalidate_lr (int left
, int right
, int top
, int bottom
)
811 int dleft
, dright
, dtop
, dbottom
;
812 int minx
, maxx
, miny
, maxy
;
818 dbottom
= Vy (bottom
);
820 minx
= MIN (dleft
, dright
);
821 maxx
= MAX (dleft
, dright
);
822 miny
= MIN (dtop
, dbottom
);
823 maxy
= MAX (dtop
, dbottom
);
827 rect
.width
= maxx
- minx
;
828 rect
.height
= maxy
- miny
;
830 redraw_region (&rect
);
831 ghid_screen_update ();
836 ghid_invalidate_all ()
838 redraw_region (NULL
);
839 ghid_screen_update ();
843 ghid_notify_crosshair_change (bool changes_complete
)
845 render_priv
*priv
= gport
->render_priv
;
847 /* We sometimes get called before the GUI is up */
848 if (gport
->drawing_area
== NULL
)
851 if (changes_complete
)
852 priv
->attached_invalidate_depth
--;
854 if (priv
->attached_invalidate_depth
< 0)
856 priv
->attached_invalidate_depth
= 0;
857 /* A mismatch of changes_complete == false and == true notifications
858 * is not expected to occur, but we will try to handle it gracefully.
859 * As we know the crosshair will have been shown already, we must
860 * repaint the entire view to be sure not to leave an artaefact.
862 ghid_invalidate_all ();
866 if (priv
->attached_invalidate_depth
== 0)
867 DrawAttached (priv
->crosshair_gc
);
869 if (!changes_complete
)
871 priv
->attached_invalidate_depth
++;
873 else if (gport
->drawing_area
!= NULL
)
875 /* Queue a GTK expose when changes are complete */
876 ghid_draw_area_update (gport
, NULL
);
881 ghid_notify_mark_change (bool changes_complete
)
883 render_priv
*priv
= gport
->render_priv
;
885 /* We sometimes get called before the GUI is up */
886 if (gport
->drawing_area
== NULL
)
889 if (changes_complete
)
890 priv
->mark_invalidate_depth
--;
892 if (priv
->mark_invalidate_depth
< 0)
894 priv
->mark_invalidate_depth
= 0;
895 /* A mismatch of changes_complete == false and == true notifications
896 * is not expected to occur, but we will try to handle it gracefully.
897 * As we know the mark will have been shown already, we must
898 * repaint the entire view to be sure not to leave an artaefact.
900 ghid_invalidate_all ();
904 if (priv
->mark_invalidate_depth
== 0)
905 DrawMark (priv
->crosshair_gc
);
907 if (!changes_complete
)
909 priv
->mark_invalidate_depth
++;
911 else if (gport
->drawing_area
!= NULL
)
913 /* Queue a GTK expose when changes are complete */
914 ghid_draw_area_update (gport
, NULL
);
919 draw_right_cross (GdkGC
*xor_gc
, gint x
, gint y
)
921 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
923 gdk_draw_line (window
, xor_gc
, x
, 0, x
, gport
->height
);
924 gdk_draw_line (window
, xor_gc
, 0, y
, gport
->width
, y
);
928 draw_slanted_cross (GdkGC
*xor_gc
, gint x
, gint y
)
930 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
933 x0
= x
+ (gport
->height
- y
);
934 x0
= MAX(0, MIN (x0
, gport
->width
));
936 x1
= MAX(0, MIN (x1
, gport
->width
));
937 y0
= y
+ (gport
->width
- x
);
938 y0
= MAX(0, MIN (y0
, gport
->height
));
940 y1
= MAX(0, MIN (y1
, gport
->height
));
941 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
943 x0
= x
- (gport
->height
- y
);
944 x0
= MAX(0, MIN (x0
, gport
->width
));
946 x1
= MAX(0, MIN (x1
, gport
->width
));
948 y0
= MAX(0, MIN (y0
, gport
->height
));
949 y1
= y
- (gport
->width
- x
);
950 y1
= MAX(0, MIN (y1
, gport
->height
));
951 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
955 draw_dozen_cross (GdkGC
*xor_gc
, gint x
, gint y
)
957 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
959 gdouble tan60
= sqrt (3);
961 x0
= x
+ (gport
->height
- y
) / tan60
;
962 x0
= MAX(0, MIN (x0
, gport
->width
));
964 x1
= MAX(0, MIN (x1
, gport
->width
));
965 y0
= y
+ (gport
->width
- x
) * tan60
;
966 y0
= MAX(0, MIN (y0
, gport
->height
));
968 y1
= MAX(0, MIN (y1
, gport
->height
));
969 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
971 x0
= x
+ (gport
->height
- y
) * tan60
;
972 x0
= MAX(0, MIN (x0
, gport
->width
));
974 x1
= MAX(0, MIN (x1
, gport
->width
));
975 y0
= y
+ (gport
->width
- x
) / tan60
;
976 y0
= MAX(0, MIN (y0
, gport
->height
));
978 y1
= MAX(0, MIN (y1
, gport
->height
));
979 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
981 x0
= x
- (gport
->height
- y
) / tan60
;
982 x0
= MAX(0, MIN (x0
, gport
->width
));
984 x1
= MAX(0, MIN (x1
, gport
->width
));
986 y0
= MAX(0, MIN (y0
, gport
->height
));
987 y1
= y
- (gport
->width
- x
) * tan60
;
988 y1
= MAX(0, MIN (y1
, gport
->height
));
989 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
991 x0
= x
- (gport
->height
- y
) * tan60
;
992 x0
= MAX(0, MIN (x0
, gport
->width
));
994 x1
= MAX(0, MIN (x1
, gport
->width
));
996 y0
= MAX(0, MIN (y0
, gport
->height
));
997 y1
= y
- (gport
->width
- x
) / tan60
;
998 y1
= MAX(0, MIN (y1
, gport
->height
));
999 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
1003 draw_crosshair (render_priv
*priv
)
1005 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
1006 GtkStyle
*style
= gtk_widget_get_style (gport
->drawing_area
);
1008 static GdkGC
*xor_gc
;
1009 static GdkColor cross_color
;
1011 if (gport
->crosshair_x
< 0 || ghidgui
->creating
|| !gport
->has_entered
)
1016 xor_gc
= gdk_gc_new (window
);
1017 gdk_gc_copy (xor_gc
, style
->white_gc
);
1018 gdk_gc_set_function (xor_gc
, GDK_XOR
);
1019 gdk_gc_set_clip_origin (xor_gc
, 0, 0);
1020 set_clip (priv
, xor_gc
);
1021 /* FIXME: when CrossColor changed from config */
1022 ghid_map_color_string (Settings
.CrossColor
, &cross_color
);
1025 gdk_gc_set_foreground (xor_gc
, &cross_color
);
1027 x
= DRAW_X (gport
->crosshair_x
);
1028 y
= DRAW_Y (gport
->crosshair_y
);
1030 draw_right_cross (xor_gc
, x
, y
);
1031 if (Crosshair
.shape
== Union_Jack_Crosshair_Shape
)
1032 draw_slanted_cross (xor_gc
, x
, y
);
1033 if (Crosshair
.shape
== Dozen_Crosshair_Shape
)
1034 draw_dozen_cross (xor_gc
, x
, y
);
1038 ghid_init_renderer (int *argc
, char ***argv
, GHidPort
*port
)
1040 /* Init any GC's required */
1041 port
->render_priv
= g_new0 (render_priv
, 1);
1042 port
->render_priv
->crosshair_gc
= gui
->graphics
->make_gc ();
1046 ghid_shutdown_renderer (GHidPort
*port
)
1048 render_priv
*priv
= port
->render_priv
;
1050 gui
->graphics
->destroy_gc (priv
->crosshair_gc
);
1051 ghid_cancel_lead_user ();
1052 g_free (port
->render_priv
);
1053 port
->render_priv
= NULL
;
1057 ghid_init_drawing_widget (GtkWidget
*widget
, GHidPort
*port
)
1062 ghid_drawing_area_configure_hook (GHidPort
*port
)
1064 static int done_once
= 0;
1065 render_priv
*priv
= port
->render_priv
;
1069 priv
->bg_gc
= gdk_gc_new (port
->drawable
);
1070 gdk_gc_set_foreground (priv
->bg_gc
, &port
->bg_color
);
1071 gdk_gc_set_clip_origin (priv
->bg_gc
, 0, 0);
1073 priv
->offlimits_gc
= gdk_gc_new (port
->drawable
);
1074 gdk_gc_set_foreground (priv
->offlimits_gc
, &port
->offlimits_color
);
1075 gdk_gc_set_clip_origin (priv
->offlimits_gc
, 0, 0);
1081 gdk_pixmap_unref (port
->mask
);
1082 port
->mask
= gdk_pixmap_new (0, port
->width
, port
->height
, 1);
1087 ghid_screen_update (void)
1089 render_priv
*priv
= gport
->render_priv
;
1090 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
1092 if (gport
->pixmap
== NULL
)
1095 gdk_draw_drawable (window
, priv
->bg_gc
, gport
->pixmap
,
1096 0, 0, 0, 0, gport
->width
, gport
->height
);
1097 draw_crosshair (priv
);
1101 ghid_drawing_area_expose_cb (GtkWidget
*widget
,
1105 render_priv
*priv
= port
->render_priv
;
1106 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
1108 gdk_draw_drawable (window
, priv
->bg_gc
, port
->pixmap
,
1109 ev
->area
.x
, ev
->area
.y
, ev
->area
.x
, ev
->area
.y
,
1110 ev
->area
.width
, ev
->area
.height
);
1111 draw_crosshair (priv
);
1116 ghid_port_drawing_realize_cb (GtkWidget
*widget
, gpointer data
)
1121 ghid_pinout_preview_expose (GtkWidget
*widget
,
1124 GhidPinoutPreview
*pinout
= GHID_PINOUT_PREVIEW (widget
);
1125 GdkWindow
*window
= gtk_widget_get_window (widget
);
1126 GdkDrawable
*save_drawable
;
1127 GtkAllocation allocation
;
1128 view_data save_view
;
1129 int save_width
, save_height
;
1130 Coord save_max_width
;
1131 Coord save_max_height
;
1133 render_priv
*priv
= gport
->render_priv
;
1135 /* Setup drawable and zoom factor for drawing routines
1137 save_drawable
= gport
->drawable
;
1138 save_view
= gport
->view
;
1139 save_width
= gport
->width
;
1140 save_height
= gport
->height
;
1141 save_max_width
= PCB
->MaxWidth
;
1142 save_max_height
= PCB
->MaxHeight
;
1144 gtk_widget_get_allocation (widget
, &allocation
);
1145 xz
= (double) pinout
->x_max
/ allocation
.width
;
1146 yz
= (double) pinout
->y_max
/ allocation
.height
;
1148 gport
->view
.coord_per_px
= xz
;
1150 gport
->view
.coord_per_px
= yz
;
1152 gport
->drawable
= window
;
1153 gport
->width
= allocation
.width
;
1154 gport
->height
= allocation
.height
;
1155 gport
->view
.width
= allocation
.width
* gport
->view
.coord_per_px
;
1156 gport
->view
.height
= allocation
.height
* gport
->view
.coord_per_px
;
1157 gport
->view
.x0
= (pinout
->x_max
- gport
->view
.width
) / 2;
1158 gport
->view
.y0
= (pinout
->y_max
- gport
->view
.height
) / 2;
1159 PCB
->MaxWidth
= pinout
->x_max
;
1160 PCB
->MaxHeight
= pinout
->y_max
;
1162 /* clear background */
1163 gdk_draw_rectangle (window
, priv
->bg_gc
, TRUE
,
1164 0, 0, allocation
.width
, allocation
.height
);
1166 /* call the drawing routine */
1167 hid_expose_callback (&ghid_hid
, NULL
, pinout
->element
);
1169 gport
->drawable
= save_drawable
;
1170 gport
->view
= save_view
;
1171 gport
->width
= save_width
;
1172 gport
->height
= save_height
;
1173 PCB
->MaxWidth
= save_max_width
;
1174 PCB
->MaxHeight
= save_max_height
;
1180 ghid_render_pixmap (int cx
, int cy
, double zoom
, int width
, int height
, int depth
)
1183 GdkDrawable
*save_drawable
;
1184 view_data save_view
;
1185 int save_width
, save_height
;
1187 render_priv
*priv
= gport
->render_priv
;
1189 save_drawable
= gport
->drawable
;
1190 save_view
= gport
->view
;
1191 save_width
= gport
->width
;
1192 save_height
= gport
->height
;
1194 pixmap
= gdk_pixmap_new (NULL
, width
, height
, depth
);
1196 /* Setup drawable and zoom factor for drawing routines
1199 gport
->drawable
= pixmap
;
1200 gport
->view
.coord_per_px
= zoom
;
1201 gport
->width
= width
;
1202 gport
->height
= height
;
1203 gport
->view
.width
= width
* gport
->view
.coord_per_px
;
1204 gport
->view
.height
= height
* gport
->view
.coord_per_px
;
1205 gport
->view
.x0
= gport
->view
.flip_x
? PCB
->MaxWidth
- cx
: cx
;
1206 gport
->view
.x0
-= gport
->view
.height
/ 2;
1207 gport
->view
.y0
= gport
->view
.flip_y
? PCB
->MaxHeight
- cy
: cy
;
1208 gport
->view
.y0
-= gport
->view
.width
/ 2;
1210 /* clear background */
1211 gdk_draw_rectangle (pixmap
, priv
->bg_gc
, TRUE
, 0, 0, width
, height
);
1213 /* call the drawing routine */
1214 region
.X1
= MIN(Px(0), Px(gport
->width
+ 1));
1215 region
.Y1
= MIN(Py(0), Py(gport
->height
+ 1));
1216 region
.X2
= MAX(Px(0), Px(gport
->width
+ 1));
1217 region
.Y2
= MAX(Py(0), Py(gport
->height
+ 1));
1219 region
.X1
= MAX (0, MIN (PCB
->MaxWidth
, region
.X1
));
1220 region
.X2
= MAX (0, MIN (PCB
->MaxWidth
, region
.X2
));
1221 region
.Y1
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y1
));
1222 region
.Y2
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y2
));
1224 hid_expose_callback (&ghid_hid
, ®ion
, NULL
);
1226 gport
->drawable
= save_drawable
;
1227 gport
->view
= save_view
;
1228 gport
->width
= save_width
;
1229 gport
->height
= save_height
;
1235 ghid_request_debug_draw (void)
1237 /* No special setup requirements, drawing goes into
1238 * the backing pixmap. */
1239 return ghid_hid
.graphics
;
1243 ghid_flush_debug_draw (void)
1245 ghid_screen_update ();
1250 ghid_finish_debug_draw (void)
1252 ghid_flush_debug_draw ();
1253 /* No special tear down requirements
1258 ghid_event_to_pcb_coords (int event_x
, int event_y
, Coord
*pcb_x
, Coord
*pcb_y
)
1260 *pcb_x
= EVENT_TO_PCB_X (event_x
);
1261 *pcb_y
= EVENT_TO_PCB_Y (event_y
);
1267 ghid_pcb_to_event_coords (Coord pcb_x
, Coord pcb_y
, int *event_x
, int *event_y
)
1269 *event_x
= DRAW_X (pcb_x
);
1270 *event_y
= DRAW_Y (pcb_y
);
1276 #define LEAD_USER_WIDTH 0.2 /* millimeters */
1277 #define LEAD_USER_PERIOD (1000 / 5) /* 5fps (in ms) */
1278 #define LEAD_USER_VELOCITY 3. /* millimeters per second */
1279 #define LEAD_USER_ARC_COUNT 3
1280 #define LEAD_USER_ARC_SEPARATION 3. /* millimeters */
1281 #define LEAD_USER_INITIAL_RADIUS 10. /* millimetres */
1282 #define LEAD_USER_COLOR_R 1.
1283 #define LEAD_USER_COLOR_G 1.
1284 #define LEAD_USER_COLOR_B 0.
1287 draw_lead_user (render_priv
*priv
)
1289 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
1290 GtkStyle
*style
= gtk_widget_get_style (gport
->drawing_area
);
1292 Coord radius
= priv
->lead_user_radius
;
1293 Coord width
= MM_TO_COORD (LEAD_USER_WIDTH
);
1294 Coord separation
= MM_TO_COORD (LEAD_USER_ARC_SEPARATION
);
1295 static GdkGC
*lead_gc
= NULL
;
1296 GdkColor lead_color
;
1298 if (!priv
->lead_user
)
1301 if (lead_gc
== NULL
)
1303 lead_gc
= gdk_gc_new (window
);
1304 gdk_gc_copy (lead_gc
, style
->white_gc
);
1305 gdk_gc_set_function (lead_gc
, GDK_XOR
);
1306 gdk_gc_set_clip_origin (lead_gc
, 0, 0);
1307 lead_color
.pixel
= 0;
1308 lead_color
.red
= (int)(65535. * LEAD_USER_COLOR_R
);
1309 lead_color
.green
= (int)(65535. * LEAD_USER_COLOR_G
);
1310 lead_color
.blue
= (int)(65535. * LEAD_USER_COLOR_B
);
1311 gdk_color_alloc (gport
->colormap
, &lead_color
);
1312 gdk_gc_set_foreground (lead_gc
, &lead_color
);
1315 set_clip (priv
, lead_gc
);
1316 gdk_gc_set_line_attributes (lead_gc
, Vz (width
),
1317 GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_MITER
);
1319 /* arcs at the approrpriate radii */
1321 for (i
= 0; i
< LEAD_USER_ARC_COUNT
; i
++, radius
-= separation
)
1324 radius
+= MM_TO_COORD (LEAD_USER_INITIAL_RADIUS
);
1326 /* Draw an arc at radius */
1327 gdk_draw_arc (gport
->drawable
, lead_gc
, FALSE
,
1328 Vx (priv
->lead_user_x
- radius
),
1329 Vy (priv
->lead_user_y
- radius
),
1330 Vz (2. * radius
), Vz (2. * radius
),
1336 lead_user_cb (gpointer data
)
1338 render_priv
*priv
= data
;
1340 double elapsed_time
;
1342 /* Queue a redraw */
1343 ghid_invalidate_all ();
1346 elapsed_time
= g_timer_elapsed (priv
->lead_user_timer
, NULL
);
1347 g_timer_start (priv
->lead_user_timer
);
1349 step
= MM_TO_COORD (LEAD_USER_VELOCITY
* elapsed_time
);
1350 if (priv
->lead_user_radius
> step
)
1351 priv
->lead_user_radius
-= step
;
1353 priv
->lead_user_radius
= MM_TO_COORD (LEAD_USER_INITIAL_RADIUS
);
1359 ghid_lead_user_to_location (Coord x
, Coord y
)
1361 render_priv
*priv
= gport
->render_priv
;
1363 ghid_cancel_lead_user ();
1365 priv
->lead_user
= true;
1366 priv
->lead_user_x
= x
;
1367 priv
->lead_user_y
= y
;
1368 priv
->lead_user_radius
= MM_TO_COORD (LEAD_USER_INITIAL_RADIUS
);
1369 priv
->lead_user_timeout
= g_timeout_add (LEAD_USER_PERIOD
, lead_user_cb
, priv
);
1370 priv
->lead_user_timer
= g_timer_new ();
1374 ghid_cancel_lead_user (void)
1376 render_priv
*priv
= gport
->render_priv
;
1378 if (priv
->lead_user_timeout
)
1379 g_source_remove (priv
->lead_user_timeout
);
1381 if (priv
->lead_user_timer
)
1382 g_timer_destroy (priv
->lead_user_timer
);
1384 if (priv
->lead_user
)
1385 ghid_invalidate_all ();
1387 priv
->lead_user_timeout
= 0;
1388 priv
->lead_user_timer
= NULL
;
1389 priv
->lead_user
= false;