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
;
48 typedef struct hid_gc_struct
62 static void draw_lead_user (render_priv
*priv
);
66 ghid_set_layer (const char *name
, int group
, int empty
)
69 if (idx
>= 0 && idx
< max_group
)
71 int n
= PCB
->LayerGroups
.Number
[group
];
72 for (idx
= 0; idx
< n
-1; idx
++)
74 int ni
= PCB
->LayerGroups
.Entries
[group
][idx
];
75 if (ni
>= 0 && ni
< max_copper_layer
+ 2
76 && PCB
->Data
->Layer
[ni
].On
)
79 idx
= PCB
->LayerGroups
.Entries
[group
][idx
];
82 if (idx
>= 0 && idx
< max_copper_layer
+ 2)
83 return /*pinout ? 1 : */ PCB
->Data
->Layer
[idx
].On
;
86 switch (SL_TYPE (idx
))
89 return /* pinout ? 0 : */ PCB
->InvisibleObjectsOn
;
91 if (SL_MYSIDE (idx
) /*&& !pinout */ )
92 return TEST_FLAG (SHOWMASKFLAG
, PCB
);
95 if (SL_MYSIDE (idx
) /*|| pinout */ )
96 return PCB
->ElementOn
;
111 ghid_destroy_gc (hidGC gc
)
114 g_object_unref (gc
->gc
);
123 rv
= g_new0 (hid_gc_struct
, 1);
124 rv
->me_pointer
= &ghid_hid
;
125 rv
->colorname
= Settings
.BackgroundColor
;
130 set_clip (render_priv
*priv
, GdkGC
*gc
)
136 gdk_gc_set_clip_rectangle (gc
, &priv
->clip_rect
);
138 gdk_gc_set_clip_mask (gc
, NULL
);
142 ghid_draw_grid (void)
144 static GdkPoint
*points
= 0;
145 static int npoints
= 0;
146 Coord x1
, y1
, x2
, y2
, x
, y
;
148 render_priv
*priv
= gport
->render_priv
;
150 if (!Settings
.DrawGrid
)
152 if (Vz (PCB
->Grid
) < MIN_GRID_DISTANCE
)
156 if (gdk_color_parse (Settings
.GridColor
, &gport
->grid_color
))
158 gport
->grid_color
.red
^= gport
->bg_color
.red
;
159 gport
->grid_color
.green
^= gport
->bg_color
.green
;
160 gport
->grid_color
.blue
^= gport
->bg_color
.blue
;
161 gdk_color_alloc (gport
->colormap
, &gport
->grid_color
);
163 priv
->grid_gc
= gdk_gc_new (gport
->drawable
);
164 gdk_gc_set_function (priv
->grid_gc
, GDK_XOR
);
165 gdk_gc_set_foreground (priv
->grid_gc
, &gport
->grid_color
);
166 gdk_gc_set_clip_origin (priv
->grid_gc
, 0, 0);
167 set_clip (priv
, priv
->grid_gc
);
169 x1
= GridFit (SIDE_X (gport
->view
.x0
), PCB
->Grid
, PCB
->GridOffsetX
);
170 y1
= GridFit (SIDE_Y (gport
->view
.y0
), PCB
->Grid
, PCB
->GridOffsetY
);
171 x2
= GridFit (SIDE_X (gport
->view
.x0
+ gport
->view
.width
- 1),
172 PCB
->Grid
, PCB
->GridOffsetX
);
173 y2
= GridFit (SIDE_Y (gport
->view
.y0
+ gport
->view
.height
- 1),
174 PCB
->Grid
, PCB
->GridOffsetY
);
191 if (Vx (x2
) >= gport
->width
)
193 if (Vy (y2
) >= gport
->height
)
195 n
= (x2
- x1
) / PCB
->Grid
+ 1;
199 points
= (GdkPoint
*)realloc (points
, npoints
* sizeof (GdkPoint
));
202 for (x
= x1
; x
<= x2
; x
+= PCB
->Grid
)
204 points
[n
].x
= Vx (x
);
209 for (y
= y1
; y
<= y2
; y
+= PCB
->Grid
)
211 for (i
= 0; i
< n
; i
++)
212 points
[i
].y
= Vy (y
);
213 gdk_draw_points (gport
->drawable
, priv
->grid_gc
, points
, n
);
217 /* ------------------------------------------------------------ */
219 ghid_draw_bg_image (void)
221 static GdkPixbuf
*pixbuf
;
222 GdkInterpType interp_type
;
223 gint x
, y
, w
, h
, w_src
, h_src
;
224 static gint w_scaled
, h_scaled
;
225 render_priv
*priv
= gport
->render_priv
;
227 if (!ghidgui
->bg_pixbuf
)
230 w
= PCB
->MaxWidth
/ gport
->view
.coord_per_px
;
231 h
= PCB
->MaxHeight
/ gport
->view
.coord_per_px
;
232 x
= gport
->view
.x0
/ gport
->view
.coord_per_px
;
233 y
= gport
->view
.y0
/ gport
->view
.coord_per_px
;
235 if (w_scaled
!= w
|| h_scaled
!= h
)
238 g_object_unref (G_OBJECT (pixbuf
));
240 w_src
= gdk_pixbuf_get_width (ghidgui
->bg_pixbuf
);
241 h_src
= gdk_pixbuf_get_height (ghidgui
->bg_pixbuf
);
242 if (w
> w_src
&& h
> h_src
)
243 interp_type
= GDK_INTERP_NEAREST
;
245 interp_type
= GDK_INTERP_BILINEAR
;
248 gdk_pixbuf_scale_simple (ghidgui
->bg_pixbuf
, w
, h
, interp_type
);
253 gdk_pixbuf_render_to_drawable (pixbuf
, gport
->drawable
, priv
->bg_gc
,
255 w
- x
, h
- y
, GDK_RGB_DITHER_NORMAL
, 0, 0);
258 #define WHICH_GC(gc) (cur_mask == HID_MASK_CLEAR ? priv->mask_gc : (gc)->gc)
261 ghid_use_mask (enum mask_mode mode
)
263 static int mask_seq_id
= 0;
265 render_priv
*priv
= gport
->render_priv
;
269 if (mode
== cur_mask
)
274 gport
->drawable
= gport
->pixmap
;
278 case HID_MASK_BEFORE
:
279 /* The HID asks not to receive this mask type, so warn if we get it */
280 g_return_if_reached ();
284 gport
->mask
= gdk_pixmap_new (0, gport
->width
, gport
->height
, 1);
285 gport
->drawable
= gport
->mask
;
289 priv
->mask_gc
= gdk_gc_new (gport
->drawable
);
290 gdk_gc_set_clip_origin (priv
->mask_gc
, 0, 0);
291 set_clip (priv
, priv
->mask_gc
);
294 gdk_gc_set_foreground (priv
->mask_gc
, &color
);
295 gdk_draw_rectangle (gport
->drawable
, priv
->mask_gc
, TRUE
, 0, 0,
296 gport
->width
, gport
->height
);
298 gdk_gc_set_foreground (priv
->mask_gc
, &color
);
305 mask_seq
= mask_seq_id
;
307 gport
->drawable
= gport
->pixmap
;
324 /* Config helper functions for when the user changes color preferences.
325 | set_special colors used in the gtkhid.
328 set_special_grid_color (void)
330 render_priv
*priv
= gport
->render_priv
;
332 if (!gport
->colormap
)
334 gport
->grid_color
.red
^= gport
->bg_color
.red
;
335 gport
->grid_color
.green
^= gport
->bg_color
.green
;
336 gport
->grid_color
.blue
^= gport
->bg_color
.blue
;
337 gdk_color_alloc (gport
->colormap
, &gport
->grid_color
);
339 gdk_gc_set_foreground (priv
->grid_gc
, &gport
->grid_color
);
343 ghid_set_special_colors (HID_Attribute
* ha
)
345 render_priv
*priv
= gport
->render_priv
;
347 if (!ha
->name
|| !ha
->value
)
349 if (!strcmp (ha
->name
, "background-color") && priv
->bg_gc
)
351 ghid_map_color_string (*(char **) ha
->value
, &gport
->bg_color
);
352 gdk_gc_set_foreground (priv
->bg_gc
, &gport
->bg_color
);
353 set_special_grid_color ();
355 else if (!strcmp (ha
->name
, "off-limit-color") && priv
->offlimits_gc
)
357 ghid_map_color_string (*(char **) ha
->value
, &gport
->offlimits_color
);
358 gdk_gc_set_foreground (priv
->offlimits_gc
, &gport
->offlimits_color
);
360 else if (!strcmp (ha
->name
, "grid-color") && priv
->grid_gc
)
362 ghid_map_color_string (*(char **) ha
->value
, &gport
->grid_color
);
363 set_special_grid_color ();
368 ghid_set_color (hidGC gc
, const char *name
)
370 static void *cache
= 0;
375 fprintf (stderr
, "%s(): name = NULL, setting to magenta\n",
380 gc
->colorname
= (char *) name
;
383 if (gport
->colormap
== 0)
384 gport
->colormap
= gtk_widget_get_colormap (gport
->top_window
);
386 if (strcmp (name
, "erase") == 0)
388 gdk_gc_set_foreground (gc
->gc
, &gport
->bg_color
);
390 else if (strcmp (name
, "drill") == 0)
392 gdk_gc_set_foreground (gc
->gc
, &gport
->offlimits_color
);
397 if (hid_cache_color (0, name
, &cval
, &cache
))
398 cc
= (ColorCache
*) cval
.ptr
;
401 cc
= (ColorCache
*) malloc (sizeof (ColorCache
));
402 memset (cc
, 0, sizeof (*cc
));
404 hid_cache_color (1, name
, &cval
, &cache
);
409 if (gdk_color_parse (name
, &cc
->color
))
410 gdk_color_alloc (gport
->colormap
, &cc
->color
);
412 gdk_color_white (gport
->colormap
, &cc
->color
);
419 cc
->xor_color
.red
= cc
->color
.red
^ gport
->bg_color
.red
;
420 cc
->xor_color
.green
= cc
->color
.green
^ gport
->bg_color
.green
;
421 cc
->xor_color
.blue
= cc
->color
.blue
^ gport
->bg_color
.blue
;
422 gdk_color_alloc (gport
->colormap
, &cc
->xor_color
);
425 gdk_gc_set_foreground (gc
->gc
, &cc
->xor_color
);
429 gdk_gc_set_foreground (gc
->gc
, &cc
->color
);
435 ghid_set_line_cap (hidGC gc
, EndCapStyle style
)
437 render_priv
*priv
= gport
->render_priv
;
443 gc
->cap
= GDK_CAP_ROUND
;
444 gc
->join
= GDK_JOIN_ROUND
;
448 gc
->cap
= GDK_CAP_PROJECTING
;
449 gc
->join
= GDK_JOIN_MITER
;
453 gdk_gc_set_line_attributes (WHICH_GC (gc
),
454 Vz (gc
->width
), GDK_LINE_SOLID
,
455 (GdkCapStyle
)gc
->cap
, (GdkJoinStyle
)gc
->join
);
459 ghid_set_line_width (hidGC gc
, Coord width
)
461 render_priv
*priv
= gport
->render_priv
;
465 gdk_gc_set_line_attributes (WHICH_GC (gc
),
466 Vz (gc
->width
), GDK_LINE_SOLID
,
467 (GdkCapStyle
)gc
->cap
, (GdkJoinStyle
)gc
->join
);
471 ghid_set_draw_xor (hidGC gc
, int xor_mask
)
473 gc
->xor_mask
= xor_mask
;
476 gdk_gc_set_function (gc
->gc
, xor_mask
? GDK_XOR
: GDK_COPY
);
477 ghid_set_color (gc
, gc
->colorname
);
483 render_priv
*priv
= gport
->render_priv
;
484 GdkWindow
*window
= gtk_widget_get_window (gport
->top_window
);
486 if (gc
->me_pointer
!= &ghid_hid
)
488 fprintf (stderr
, "Fatal: GC from another HID passed to GTK HID\n");
496 gc
->gc
= gdk_gc_new (window
);
497 ghid_set_color (gc
, gc
->colorname
);
498 ghid_set_line_width (gc
, gc
->width
);
499 ghid_set_line_cap (gc
, (EndCapStyle
)gc
->cap
);
500 ghid_set_draw_xor (gc
, gc
->xor_mask
);
501 gdk_gc_set_clip_origin (gc
->gc
, 0, 0);
503 if (gc
->mask_seq
!= mask_seq
)
506 gdk_gc_set_clip_mask (gc
->gc
, gport
->mask
);
508 set_clip (priv
, gc
->gc
);
509 gc
->mask_seq
= mask_seq
;
511 priv
->u_gc
= WHICH_GC (gc
);
516 ghid_draw_line (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
518 double dx1
, dy1
, dx2
, dy2
;
519 render_priv
*priv
= gport
->render_priv
;
521 dx1
= Vx ((double) x1
);
522 dy1
= Vy ((double) y1
);
523 dx2
= Vx ((double) x2
);
524 dy2
= Vy ((double) y2
);
526 if (!ClipLine (0, 0, gport
->width
, gport
->height
,
527 &dx1
, &dy1
, &dx2
, &dy2
, gc
->width
/ gport
->view
.coord_per_px
))
531 gdk_draw_line (gport
->drawable
, priv
->u_gc
, dx1
, dy1
, dx2
, dy2
);
535 ghid_draw_arc (hidGC gc
, Coord cx
, Coord cy
,
536 Coord xradius
, Coord yradius
, Angle start_angle
, Angle delta_angle
)
540 render_priv
*priv
= gport
->render_priv
;
542 w
= gport
->width
* gport
->view
.coord_per_px
;
543 h
= gport
->height
* gport
->view
.coord_per_px
;
544 radius
= (xradius
> yradius
) ? xradius
: yradius
;
545 if (SIDE_X (cx
) < gport
->view
.x0
- radius
546 || SIDE_X (cx
) > gport
->view
.x0
+ w
+ radius
547 || SIDE_Y (cy
) < gport
->view
.y0
- radius
548 || SIDE_Y (cy
) > gport
->view
.y0
+ h
+ radius
)
555 if (gport
->view
.flip_x
)
557 start_angle
= 180 - start_angle
;
558 delta_angle
= -delta_angle
;
560 if (gport
->view
.flip_y
)
562 start_angle
= -start_angle
;
563 delta_angle
= -delta_angle
;
565 /* make sure we fall in the -180 to +180 range */
566 start_angle
= NormalizeAngle (start_angle
);
567 if (start_angle
>= 180) start_angle
-= 360;
569 gdk_draw_arc (gport
->drawable
, priv
->u_gc
, 0,
570 Vx (cx
) - vrx
, Vy (cy
) - vry
,
571 vrx
* 2, vry
* 2, (start_angle
+ 180) * 64, delta_angle
* 64);
575 ghid_draw_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
578 render_priv
*priv
= gport
->render_priv
;
581 w
= gport
->width
* gport
->view
.coord_per_px
;
582 h
= gport
->height
* gport
->view
.coord_per_px
;
584 if ((SIDE_X (x1
) < gport
->view
.x0
- lw
585 && SIDE_X (x2
) < gport
->view
.x0
- lw
)
586 || (SIDE_X (x1
) > gport
->view
.x0
+ w
+ lw
587 && SIDE_X (x2
) > gport
->view
.x0
+ w
+ lw
)
588 || (SIDE_Y (y1
) < gport
->view
.y0
- lw
589 && SIDE_Y (y2
) < gport
->view
.y0
- lw
)
590 || (SIDE_Y (y1
) > gport
->view
.y0
+ h
+ lw
591 && SIDE_Y (y2
) > gport
->view
.y0
+ h
+ lw
))
613 gdk_draw_rectangle (gport
->drawable
, priv
->u_gc
, FALSE
,
614 x1
, y1
, x2
- x1
+ 1, y2
- y1
+ 1);
619 ghid_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
)
622 render_priv
*priv
= gport
->render_priv
;
624 w
= gport
->width
* gport
->view
.coord_per_px
;
625 h
= gport
->height
* gport
->view
.coord_per_px
;
626 if (SIDE_X (cx
) < gport
->view
.x0
- radius
627 || SIDE_X (cx
) > gport
->view
.x0
+ w
+ radius
628 || SIDE_Y (cy
) < gport
->view
.y0
- radius
629 || SIDE_Y (cy
) > gport
->view
.y0
+ h
+ radius
)
634 gdk_draw_arc (gport
->drawable
, priv
->u_gc
, TRUE
,
635 Vx (cx
) - vr
, Vy (cy
) - vr
, vr
* 2, vr
* 2, 0, 360 * 64);
639 ghid_fill_polygon (hidGC gc
, int n_coords
, Coord
*x
, Coord
*y
)
641 static GdkPoint
*points
= 0;
642 static int npoints
= 0;
644 render_priv
*priv
= gport
->render_priv
;
647 if (npoints
< n_coords
)
649 npoints
= n_coords
+ 1;
650 points
= (GdkPoint
*)realloc (points
, npoints
* sizeof (GdkPoint
));
652 for (i
= 0; i
< n_coords
; i
++)
654 points
[i
].x
= Vx (x
[i
]);
655 points
[i
].y
= Vy (y
[i
]);
657 gdk_draw_polygon (gport
->drawable
, priv
->u_gc
, 1, points
, n_coords
);
661 ghid_fill_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
663 gint w
, h
, lw
, xx
, yy
;
664 render_priv
*priv
= gport
->render_priv
;
667 w
= gport
->width
* gport
->view
.coord_per_px
;
668 h
= gport
->height
* gport
->view
.coord_per_px
;
670 if ((SIDE_X (x1
) < gport
->view
.x0
- lw
671 && SIDE_X (x2
) < gport
->view
.x0
- lw
)
672 || (SIDE_X (x1
) > gport
->view
.x0
+ w
+ lw
673 && SIDE_X (x2
) > gport
->view
.x0
+ w
+ lw
)
674 || (SIDE_Y (y1
) < gport
->view
.y0
- lw
675 && SIDE_Y (y2
) < gport
->view
.y0
- lw
)
676 || (SIDE_Y (y1
) > gport
->view
.y0
+ h
+ lw
677 && SIDE_Y (y2
) > gport
->view
.y0
+ h
+ lw
))
697 gdk_draw_rectangle (gport
->drawable
, priv
->u_gc
, TRUE
,
698 x1
, y1
, x2
- x1
+ 1, y2
- y1
+ 1);
702 redraw_region (GdkRectangle
*rect
)
704 int eleft
, eright
, etop
, ebottom
;
706 render_priv
*priv
= gport
->render_priv
;
713 priv
->clip_rect
= *rect
;
718 priv
->clip_rect
.x
= 0;
719 priv
->clip_rect
.y
= 0;
720 priv
->clip_rect
.width
= gport
->width
;
721 priv
->clip_rect
.height
= gport
->height
;
725 set_clip (priv
, priv
->bg_gc
);
726 set_clip (priv
, priv
->offlimits_gc
);
727 set_clip (priv
, priv
->mask_gc
);
728 set_clip (priv
, priv
->grid_gc
);
730 region
.X1
= MIN(Px(priv
->clip_rect
.x
),
731 Px(priv
->clip_rect
.x
+ priv
->clip_rect
.width
+ 1));
732 region
.Y1
= MIN(Py(priv
->clip_rect
.y
),
733 Py(priv
->clip_rect
.y
+ priv
->clip_rect
.height
+ 1));
734 region
.X2
= MAX(Px(priv
->clip_rect
.x
),
735 Px(priv
->clip_rect
.x
+ priv
->clip_rect
.width
+ 1));
736 region
.Y2
= MAX(Py(priv
->clip_rect
.y
),
737 Py(priv
->clip_rect
.y
+ priv
->clip_rect
.height
+ 1));
739 region
.X1
= MAX (0, MIN (PCB
->MaxWidth
, region
.X1
));
740 region
.X2
= MAX (0, MIN (PCB
->MaxWidth
, region
.X2
));
741 region
.Y1
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y1
));
742 region
.Y2
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y2
));
745 eright
= Vx (PCB
->MaxWidth
);
747 ebottom
= Vy (PCB
->MaxHeight
);
762 gdk_draw_rectangle (gport
->drawable
, priv
->offlimits_gc
,
763 1, 0, 0, eleft
, gport
->height
);
766 if (eright
< gport
->width
)
767 gdk_draw_rectangle (gport
->drawable
, priv
->offlimits_gc
,
768 1, eright
, 0, gport
->width
- eright
, gport
->height
);
770 eright
= gport
->width
;
772 gdk_draw_rectangle (gport
->drawable
, priv
->offlimits_gc
,
773 1, eleft
, 0, eright
- eleft
+ 1, etop
);
776 if (ebottom
< gport
->height
)
777 gdk_draw_rectangle (gport
->drawable
, priv
->offlimits_gc
,
778 1, eleft
, ebottom
, eright
- eleft
+ 1,
779 gport
->height
- ebottom
);
781 ebottom
= gport
->height
;
783 gdk_draw_rectangle (gport
->drawable
, priv
->bg_gc
, 1,
784 eleft
, etop
, eright
- eleft
+ 1, ebottom
- etop
+ 1);
786 ghid_draw_bg_image();
788 hid_expose_callback (&ghid_hid
, ®ion
, 0);
791 /* In some cases we are called with the crosshair still off */
792 if (priv
->attached_invalidate_depth
== 0)
795 /* In some cases we are called with the mark still off */
796 if (priv
->mark_invalidate_depth
== 0)
799 draw_lead_user (priv
);
803 /* Rest the clip for bg_gc, as it is used outside this function */
804 gdk_gc_set_clip_mask (priv
->bg_gc
, NULL
);
808 ghid_invalidate_lr (int left
, int right
, int top
, int bottom
)
810 int dleft
, dright
, dtop
, dbottom
;
811 int minx
, maxx
, miny
, maxy
;
817 dbottom
= Vy (bottom
);
819 minx
= MIN (dleft
, dright
);
820 maxx
= MAX (dleft
, dright
);
821 miny
= MIN (dtop
, dbottom
);
822 maxy
= MAX (dtop
, dbottom
);
826 rect
.width
= maxx
- minx
;
827 rect
.height
= maxy
- miny
;
829 redraw_region (&rect
);
830 ghid_screen_update ();
835 ghid_invalidate_all ()
837 redraw_region (NULL
);
838 ghid_screen_update ();
842 ghid_notify_crosshair_change (bool changes_complete
)
844 render_priv
*priv
= gport
->render_priv
;
846 /* We sometimes get called before the GUI is up */
847 if (gport
->drawing_area
== NULL
)
850 if (changes_complete
)
851 priv
->attached_invalidate_depth
--;
853 if (priv
->attached_invalidate_depth
< 0)
855 priv
->attached_invalidate_depth
= 0;
856 /* A mismatch of changes_complete == false and == true notifications
857 * is not expected to occur, but we will try to handle it gracefully.
858 * As we know the crosshair will have been shown already, we must
859 * repaint the entire view to be sure not to leave an artaefact.
861 ghid_invalidate_all ();
865 if (priv
->attached_invalidate_depth
== 0)
868 if (!changes_complete
)
870 priv
->attached_invalidate_depth
++;
872 else if (gport
->drawing_area
!= NULL
)
874 /* Queue a GTK expose when changes are complete */
875 ghid_draw_area_update (gport
, NULL
);
880 ghid_notify_mark_change (bool changes_complete
)
882 render_priv
*priv
= gport
->render_priv
;
884 /* We sometimes get called before the GUI is up */
885 if (gport
->drawing_area
== NULL
)
888 if (changes_complete
)
889 priv
->mark_invalidate_depth
--;
891 if (priv
->mark_invalidate_depth
< 0)
893 priv
->mark_invalidate_depth
= 0;
894 /* A mismatch of changes_complete == false and == true notifications
895 * is not expected to occur, but we will try to handle it gracefully.
896 * As we know the mark will have been shown already, we must
897 * repaint the entire view to be sure not to leave an artaefact.
899 ghid_invalidate_all ();
903 if (priv
->mark_invalidate_depth
== 0)
906 if (!changes_complete
)
908 priv
->mark_invalidate_depth
++;
910 else if (gport
->drawing_area
!= NULL
)
912 /* Queue a GTK expose when changes are complete */
913 ghid_draw_area_update (gport
, NULL
);
918 draw_right_cross (GdkGC
*xor_gc
, gint x
, gint y
)
920 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
922 gdk_draw_line (window
, xor_gc
, x
, 0, x
, gport
->height
);
923 gdk_draw_line (window
, xor_gc
, 0, y
, gport
->width
, y
);
927 draw_slanted_cross (GdkGC
*xor_gc
, gint x
, gint y
)
929 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
932 x0
= x
+ (gport
->height
- y
);
933 x0
= MAX(0, MIN (x0
, gport
->width
));
935 x1
= MAX(0, MIN (x1
, gport
->width
));
936 y0
= y
+ (gport
->width
- x
);
937 y0
= MAX(0, MIN (y0
, gport
->height
));
939 y1
= MAX(0, MIN (y1
, gport
->height
));
940 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
942 x0
= x
- (gport
->height
- y
);
943 x0
= MAX(0, MIN (x0
, gport
->width
));
945 x1
= MAX(0, MIN (x1
, gport
->width
));
947 y0
= MAX(0, MIN (y0
, gport
->height
));
948 y1
= y
- (gport
->width
- x
);
949 y1
= MAX(0, MIN (y1
, gport
->height
));
950 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
954 draw_dozen_cross (GdkGC
*xor_gc
, gint x
, gint y
)
956 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
958 gdouble tan60
= sqrt (3);
960 x0
= x
+ (gport
->height
- y
) / tan60
;
961 x0
= MAX(0, MIN (x0
, gport
->width
));
963 x1
= MAX(0, MIN (x1
, gport
->width
));
964 y0
= y
+ (gport
->width
- x
) * tan60
;
965 y0
= MAX(0, MIN (y0
, gport
->height
));
967 y1
= MAX(0, MIN (y1
, gport
->height
));
968 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
970 x0
= x
+ (gport
->height
- y
) * tan60
;
971 x0
= MAX(0, MIN (x0
, gport
->width
));
973 x1
= MAX(0, MIN (x1
, gport
->width
));
974 y0
= y
+ (gport
->width
- x
) / tan60
;
975 y0
= MAX(0, MIN (y0
, gport
->height
));
977 y1
= MAX(0, MIN (y1
, gport
->height
));
978 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
980 x0
= x
- (gport
->height
- y
) / tan60
;
981 x0
= MAX(0, MIN (x0
, gport
->width
));
983 x1
= MAX(0, MIN (x1
, gport
->width
));
985 y0
= MAX(0, MIN (y0
, gport
->height
));
986 y1
= y
- (gport
->width
- x
) * tan60
;
987 y1
= MAX(0, MIN (y1
, gport
->height
));
988 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
990 x0
= x
- (gport
->height
- y
) * tan60
;
991 x0
= MAX(0, MIN (x0
, gport
->width
));
993 x1
= MAX(0, MIN (x1
, gport
->width
));
995 y0
= MAX(0, MIN (y0
, gport
->height
));
996 y1
= y
- (gport
->width
- x
) / tan60
;
997 y1
= MAX(0, MIN (y1
, gport
->height
));
998 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
1002 draw_crosshair (render_priv
*priv
)
1004 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
1005 GtkStyle
*style
= gtk_widget_get_style (gport
->drawing_area
);
1007 static GdkGC
*xor_gc
;
1008 static GdkColor cross_color
;
1010 if (gport
->crosshair_x
< 0 || ghidgui
->creating
|| !gport
->has_entered
)
1015 xor_gc
= gdk_gc_new (window
);
1016 gdk_gc_copy (xor_gc
, style
->white_gc
);
1017 gdk_gc_set_function (xor_gc
, GDK_XOR
);
1018 gdk_gc_set_clip_origin (xor_gc
, 0, 0);
1019 set_clip (priv
, xor_gc
);
1020 /* FIXME: when CrossColor changed from config */
1021 ghid_map_color_string (Settings
.CrossColor
, &cross_color
);
1024 gdk_gc_set_foreground (xor_gc
, &cross_color
);
1026 x
= DRAW_X (gport
->crosshair_x
);
1027 y
= DRAW_Y (gport
->crosshair_y
);
1029 draw_right_cross (xor_gc
, x
, y
);
1030 if (Crosshair
.shape
== Union_Jack_Crosshair_Shape
)
1031 draw_slanted_cross (xor_gc
, x
, y
);
1032 if (Crosshair
.shape
== Dozen_Crosshair_Shape
)
1033 draw_dozen_cross (xor_gc
, x
, y
);
1037 ghid_init_renderer (int *argc
, char ***argv
, GHidPort
*port
)
1039 /* Init any GC's required */
1040 port
->render_priv
= g_new0 (render_priv
, 1);
1044 ghid_shutdown_renderer (GHidPort
*port
)
1046 ghid_cancel_lead_user ();
1047 g_free (port
->render_priv
);
1048 port
->render_priv
= NULL
;
1052 ghid_init_drawing_widget (GtkWidget
*widget
, GHidPort
*port
)
1057 ghid_drawing_area_configure_hook (GHidPort
*port
)
1059 static int done_once
= 0;
1060 render_priv
*priv
= port
->render_priv
;
1064 priv
->bg_gc
= gdk_gc_new (port
->drawable
);
1065 gdk_gc_set_foreground (priv
->bg_gc
, &port
->bg_color
);
1066 gdk_gc_set_clip_origin (priv
->bg_gc
, 0, 0);
1068 priv
->offlimits_gc
= gdk_gc_new (port
->drawable
);
1069 gdk_gc_set_foreground (priv
->offlimits_gc
, &port
->offlimits_color
);
1070 gdk_gc_set_clip_origin (priv
->offlimits_gc
, 0, 0);
1076 gdk_pixmap_unref (port
->mask
);
1077 port
->mask
= gdk_pixmap_new (0, port
->width
, port
->height
, 1);
1082 ghid_screen_update (void)
1084 render_priv
*priv
= gport
->render_priv
;
1085 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
1087 if (gport
->pixmap
== NULL
)
1090 gdk_draw_drawable (window
, priv
->bg_gc
, gport
->pixmap
,
1091 0, 0, 0, 0, gport
->width
, gport
->height
);
1092 draw_crosshair (priv
);
1096 ghid_drawing_area_expose_cb (GtkWidget
*widget
,
1100 render_priv
*priv
= port
->render_priv
;
1101 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
1103 gdk_draw_drawable (window
, priv
->bg_gc
, port
->pixmap
,
1104 ev
->area
.x
, ev
->area
.y
, ev
->area
.x
, ev
->area
.y
,
1105 ev
->area
.width
, ev
->area
.height
);
1106 draw_crosshair (priv
);
1111 ghid_port_drawing_realize_cb (GtkWidget
*widget
, gpointer data
)
1116 ghid_pinout_preview_expose (GtkWidget
*widget
,
1119 GhidPinoutPreview
*pinout
= GHID_PINOUT_PREVIEW (widget
);
1120 GdkWindow
*window
= gtk_widget_get_window (widget
);
1121 GdkDrawable
*save_drawable
;
1122 GtkAllocation allocation
;
1123 view_data save_view
;
1124 int save_width
, save_height
;
1125 Coord save_max_width
;
1126 Coord save_max_height
;
1128 render_priv
*priv
= gport
->render_priv
;
1130 /* Setup drawable and zoom factor for drawing routines
1132 save_drawable
= gport
->drawable
;
1133 save_view
= gport
->view
;
1134 save_width
= gport
->width
;
1135 save_height
= gport
->height
;
1136 save_max_width
= PCB
->MaxWidth
;
1137 save_max_height
= PCB
->MaxHeight
;
1139 gtk_widget_get_allocation (widget
, &allocation
);
1140 xz
= (double) pinout
->x_max
/ allocation
.width
;
1141 yz
= (double) pinout
->y_max
/ allocation
.height
;
1143 gport
->view
.coord_per_px
= xz
;
1145 gport
->view
.coord_per_px
= yz
;
1147 gport
->drawable
= window
;
1148 gport
->width
= allocation
.width
;
1149 gport
->height
= allocation
.height
;
1150 gport
->view
.width
= allocation
.width
* gport
->view
.coord_per_px
;
1151 gport
->view
.height
= allocation
.height
* gport
->view
.coord_per_px
;
1152 gport
->view
.x0
= (pinout
->x_max
- gport
->view
.width
) / 2;
1153 gport
->view
.y0
= (pinout
->y_max
- gport
->view
.height
) / 2;
1154 PCB
->MaxWidth
= pinout
->x_max
;
1155 PCB
->MaxHeight
= pinout
->y_max
;
1157 /* clear background */
1158 gdk_draw_rectangle (window
, priv
->bg_gc
, TRUE
,
1159 0, 0, allocation
.width
, allocation
.height
);
1161 /* call the drawing routine */
1162 hid_expose_callback (&ghid_hid
, NULL
, &pinout
->element
);
1164 gport
->drawable
= save_drawable
;
1165 gport
->view
= save_view
;
1166 gport
->width
= save_width
;
1167 gport
->height
= save_height
;
1168 PCB
->MaxWidth
= save_max_width
;
1169 PCB
->MaxHeight
= save_max_height
;
1175 ghid_render_pixmap (int cx
, int cy
, double zoom
, int width
, int height
, int depth
)
1178 GdkDrawable
*save_drawable
;
1179 view_data save_view
;
1180 int save_width
, save_height
;
1182 render_priv
*priv
= gport
->render_priv
;
1184 save_drawable
= gport
->drawable
;
1185 save_view
= gport
->view
;
1186 save_width
= gport
->width
;
1187 save_height
= gport
->height
;
1189 pixmap
= gdk_pixmap_new (NULL
, width
, height
, depth
);
1191 /* Setup drawable and zoom factor for drawing routines
1194 gport
->drawable
= pixmap
;
1195 gport
->view
.coord_per_px
= zoom
;
1196 gport
->width
= width
;
1197 gport
->height
= height
;
1198 gport
->view
.width
= width
* gport
->view
.coord_per_px
;
1199 gport
->view
.height
= height
* gport
->view
.coord_per_px
;
1200 gport
->view
.x0
= gport
->view
.flip_x
? PCB
->MaxWidth
- cx
: cx
;
1201 gport
->view
.x0
-= gport
->view
.height
/ 2;
1202 gport
->view
.y0
= gport
->view
.flip_y
? PCB
->MaxHeight
- cy
: cy
;
1203 gport
->view
.y0
-= gport
->view
.width
/ 2;
1205 /* clear background */
1206 gdk_draw_rectangle (pixmap
, priv
->bg_gc
, TRUE
, 0, 0, width
, height
);
1208 /* call the drawing routine */
1209 region
.X1
= MIN(Px(0), Px(gport
->width
+ 1));
1210 region
.Y1
= MIN(Py(0), Py(gport
->height
+ 1));
1211 region
.X2
= MAX(Px(0), Px(gport
->width
+ 1));
1212 region
.Y2
= MAX(Py(0), Py(gport
->height
+ 1));
1214 region
.X1
= MAX (0, MIN (PCB
->MaxWidth
, region
.X1
));
1215 region
.X2
= MAX (0, MIN (PCB
->MaxWidth
, region
.X2
));
1216 region
.Y1
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y1
));
1217 region
.Y2
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y2
));
1219 hid_expose_callback (&ghid_hid
, ®ion
, NULL
);
1221 gport
->drawable
= save_drawable
;
1222 gport
->view
= save_view
;
1223 gport
->width
= save_width
;
1224 gport
->height
= save_height
;
1230 ghid_request_debug_draw (void)
1232 /* No special setup requirements, drawing goes into
1233 * the backing pixmap. */
1238 ghid_flush_debug_draw (void)
1240 ghid_screen_update ();
1245 ghid_finish_debug_draw (void)
1247 ghid_flush_debug_draw ();
1248 /* No special tear down requirements
1253 ghid_event_to_pcb_coords (int event_x
, int event_y
, Coord
*pcb_x
, Coord
*pcb_y
)
1255 *pcb_x
= EVENT_TO_PCB_X (event_x
);
1256 *pcb_y
= EVENT_TO_PCB_Y (event_y
);
1262 ghid_pcb_to_event_coords (Coord pcb_x
, Coord pcb_y
, int *event_x
, int *event_y
)
1264 *event_x
= DRAW_X (pcb_x
);
1265 *event_y
= DRAW_Y (pcb_y
);
1271 #define LEAD_USER_WIDTH 0.2 /* millimeters */
1272 #define LEAD_USER_PERIOD (1000 / 5) /* 5fps (in ms) */
1273 #define LEAD_USER_VELOCITY 3. /* millimeters per second */
1274 #define LEAD_USER_ARC_COUNT 3
1275 #define LEAD_USER_ARC_SEPARATION 3. /* millimeters */
1276 #define LEAD_USER_INITIAL_RADIUS 10. /* millimetres */
1277 #define LEAD_USER_COLOR_R 1.
1278 #define LEAD_USER_COLOR_G 1.
1279 #define LEAD_USER_COLOR_B 0.
1282 draw_lead_user (render_priv
*priv
)
1284 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
1285 GtkStyle
*style
= gtk_widget_get_style (gport
->drawing_area
);
1287 Coord radius
= priv
->lead_user_radius
;
1288 Coord width
= MM_TO_COORD (LEAD_USER_WIDTH
);
1289 Coord separation
= MM_TO_COORD (LEAD_USER_ARC_SEPARATION
);
1290 static GdkGC
*lead_gc
= NULL
;
1291 GdkColor lead_color
;
1293 if (!priv
->lead_user
)
1296 if (lead_gc
== NULL
)
1298 lead_gc
= gdk_gc_new (window
);
1299 gdk_gc_copy (lead_gc
, style
->white_gc
);
1300 gdk_gc_set_function (lead_gc
, GDK_XOR
);
1301 gdk_gc_set_clip_origin (lead_gc
, 0, 0);
1302 lead_color
.pixel
= 0;
1303 lead_color
.red
= (int)(65535. * LEAD_USER_COLOR_R
);
1304 lead_color
.green
= (int)(65535. * LEAD_USER_COLOR_G
);
1305 lead_color
.blue
= (int)(65535. * LEAD_USER_COLOR_B
);
1306 gdk_color_alloc (gport
->colormap
, &lead_color
);
1307 gdk_gc_set_foreground (lead_gc
, &lead_color
);
1310 set_clip (priv
, lead_gc
);
1311 gdk_gc_set_line_attributes (lead_gc
, Vz (width
),
1312 GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_MITER
);
1314 /* arcs at the approrpriate radii */
1316 for (i
= 0; i
< LEAD_USER_ARC_COUNT
; i
++, radius
-= separation
)
1319 radius
+= MM_TO_COORD (LEAD_USER_INITIAL_RADIUS
);
1321 /* Draw an arc at radius */
1322 gdk_draw_arc (gport
->drawable
, lead_gc
, FALSE
,
1323 Vx (priv
->lead_user_x
- radius
),
1324 Vy (priv
->lead_user_y
- radius
),
1325 Vz (2. * radius
), Vz (2. * radius
),
1331 lead_user_cb (gpointer data
)
1333 render_priv
*priv
= data
;
1335 double elapsed_time
;
1337 /* Queue a redraw */
1338 ghid_invalidate_all ();
1341 elapsed_time
= g_timer_elapsed (priv
->lead_user_timer
, NULL
);
1342 g_timer_start (priv
->lead_user_timer
);
1344 step
= MM_TO_COORD (LEAD_USER_VELOCITY
* elapsed_time
);
1345 if (priv
->lead_user_radius
> step
)
1346 priv
->lead_user_radius
-= step
;
1348 priv
->lead_user_radius
= MM_TO_COORD (LEAD_USER_INITIAL_RADIUS
);
1354 ghid_lead_user_to_location (Coord x
, Coord y
)
1356 render_priv
*priv
= gport
->render_priv
;
1358 ghid_cancel_lead_user ();
1360 priv
->lead_user
= true;
1361 priv
->lead_user_x
= x
;
1362 priv
->lead_user_y
= y
;
1363 priv
->lead_user_radius
= MM_TO_COORD (LEAD_USER_INITIAL_RADIUS
);
1364 priv
->lead_user_timeout
= g_timeout_add (LEAD_USER_PERIOD
, lead_user_cb
, priv
);
1365 priv
->lead_user_timer
= g_timer_new ();
1369 ghid_cancel_lead_user (void)
1371 render_priv
*priv
= gport
->render_priv
;
1373 if (priv
->lead_user_timeout
)
1374 g_source_remove (priv
->lead_user_timeout
);
1376 if (priv
->lead_user_timer
)
1377 g_timer_destroy (priv
->lead_user_timer
);
1379 if (priv
->lead_user
)
1380 ghid_invalidate_all ();
1382 priv
->lead_user_timeout
= 0;
1383 priv
->lead_user_timer
= NULL
;
1384 priv
->lead_user
= false;