11 #include "hid/common/draw_helpers.h"
13 #ifdef HAVE_LIBDMALLOC
18 extern HID_DRAW ghid_graphics
;
20 /* Sets priv->u_gc to the "right" GC to use (wrt mask or window)
22 #define USE_GC(gc) if (!use_gc(gc)) return
24 static enum mask_mode cur_mask
= HID_MASK_OFF
;
25 static int mask_seq
= 0;
27 typedef struct render_priv
{
34 GdkRectangle clip_rect
;
35 int attached_invalidate_depth
;
36 int mark_invalidate_depth
;
38 /* Feature for leading the user to a particular location */
39 guint lead_user_timeout
;
40 GTimer
*lead_user_timer
;
42 Coord lead_user_radius
;
50 typedef struct gtk_gc_struct
52 struct hid_gc_struct hid_gc
; /* Parent */
64 static void draw_lead_user (render_priv
*priv
);
68 ghid_set_layer (const char *name
, int group
, int empty
)
71 if (idx
>= 0 && idx
< max_group
)
73 int n
= PCB
->LayerGroups
.Number
[group
];
74 for (idx
= 0; idx
< n
-1; idx
++)
76 int ni
= PCB
->LayerGroups
.Entries
[group
][idx
];
77 if (ni
>= 0 && ni
< max_copper_layer
+ 2
78 && PCB
->Data
->Layer
[ni
].On
)
81 idx
= PCB
->LayerGroups
.Entries
[group
][idx
];
84 if (idx
>= 0 && idx
< max_copper_layer
+ 2)
85 return /*pinout ? 1 : */ PCB
->Data
->Layer
[idx
].On
;
88 switch (SL_TYPE (idx
))
91 return /* pinout ? 0 : */ PCB
->InvisibleObjectsOn
;
93 if (SL_MYSIDE (idx
) /*&& !pinout */ )
94 return TEST_FLAG (SHOWMASKFLAG
, PCB
);
97 if (SL_MYSIDE (idx
) /*|| pinout */ )
98 return PCB
->ElementOn
;
113 ghid_destroy_gc (hidGC gc
)
115 gtkGC gtk_gc
= (gtkGC
)gc
;
118 g_object_unref (gtk_gc
->gdk_gc
);
125 hidGC gc
= (hidGC
)g_new0 (struct gtk_gc_struct
, 1);
126 gtkGC gtk_gc
= (gtkGC
)gc
;
129 gc
->hid_draw
= &ghid_graphics
;
131 gtk_gc
->colorname
= Settings
.BackgroundColor
;
137 set_clip (render_priv
*priv
, GdkGC
*gc
)
143 gdk_gc_set_clip_rectangle (gc
, &priv
->clip_rect
);
145 gdk_gc_set_clip_mask (gc
, NULL
);
149 ghid_draw_grid (void)
151 static GdkPoint
*points
= 0;
152 static int npoints
= 0;
153 Coord x1
, y1
, x2
, y2
, x
, y
;
155 render_priv
*priv
= gport
->render_priv
;
157 if (!Settings
.DrawGrid
)
159 if (Vz (PCB
->Grid
) < MIN_GRID_DISTANCE
)
163 if (gdk_color_parse (Settings
.GridColor
, &gport
->grid_color
))
165 gport
->grid_color
.red
^= gport
->bg_color
.red
;
166 gport
->grid_color
.green
^= gport
->bg_color
.green
;
167 gport
->grid_color
.blue
^= gport
->bg_color
.blue
;
168 gdk_color_alloc (gport
->colormap
, &gport
->grid_color
);
170 priv
->grid_gc
= gdk_gc_new (gport
->drawable
);
171 gdk_gc_set_function (priv
->grid_gc
, GDK_XOR
);
172 gdk_gc_set_foreground (priv
->grid_gc
, &gport
->grid_color
);
173 gdk_gc_set_clip_origin (priv
->grid_gc
, 0, 0);
174 set_clip (priv
, priv
->grid_gc
);
176 x1
= GridFit (SIDE_X (gport
->view
.x0
), PCB
->Grid
, PCB
->GridOffsetX
);
177 y1
= GridFit (SIDE_Y (gport
->view
.y0
), PCB
->Grid
, PCB
->GridOffsetY
);
178 x2
= GridFit (SIDE_X (gport
->view
.x0
+ gport
->view
.width
- 1),
179 PCB
->Grid
, PCB
->GridOffsetX
);
180 y2
= GridFit (SIDE_Y (gport
->view
.y0
+ gport
->view
.height
- 1),
181 PCB
->Grid
, PCB
->GridOffsetY
);
198 if (Vx (x2
) >= gport
->width
)
200 if (Vy (y2
) >= gport
->height
)
202 n
= (x2
- x1
) / PCB
->Grid
+ 1;
206 points
= (GdkPoint
*)realloc (points
, npoints
* sizeof (GdkPoint
));
209 for (x
= x1
; x
<= x2
; x
+= PCB
->Grid
)
211 points
[n
].x
= Vx (x
);
216 for (y
= y1
; y
<= y2
; y
+= PCB
->Grid
)
218 for (i
= 0; i
< n
; i
++)
219 points
[i
].y
= Vy (y
);
220 gdk_draw_points (gport
->drawable
, priv
->grid_gc
, points
, n
);
224 /* ------------------------------------------------------------ */
226 ghid_draw_bg_image (void)
228 static GdkPixbuf
*pixbuf
;
229 GdkInterpType interp_type
;
230 gint x
, y
, w
, h
, w_src
, h_src
;
231 static gint w_scaled
, h_scaled
;
232 render_priv
*priv
= gport
->render_priv
;
234 if (!ghidgui
->bg_pixbuf
)
237 w
= PCB
->MaxWidth
/ gport
->view
.coord_per_px
;
238 h
= PCB
->MaxHeight
/ gport
->view
.coord_per_px
;
239 x
= gport
->view
.x0
/ gport
->view
.coord_per_px
;
240 y
= gport
->view
.y0
/ gport
->view
.coord_per_px
;
242 if (w_scaled
!= w
|| h_scaled
!= h
)
245 g_object_unref (G_OBJECT (pixbuf
));
247 w_src
= gdk_pixbuf_get_width (ghidgui
->bg_pixbuf
);
248 h_src
= gdk_pixbuf_get_height (ghidgui
->bg_pixbuf
);
249 if (w
> w_src
&& h
> h_src
)
250 interp_type
= GDK_INTERP_NEAREST
;
252 interp_type
= GDK_INTERP_BILINEAR
;
255 gdk_pixbuf_scale_simple (ghidgui
->bg_pixbuf
, w
, h
, interp_type
);
260 gdk_pixbuf_render_to_drawable (pixbuf
, gport
->drawable
, priv
->bg_gc
,
262 w
- x
, h
- y
, GDK_RGB_DITHER_NORMAL
, 0, 0);
265 #define WHICH_GC(gtk_gc) (cur_mask == HID_MASK_CLEAR ? priv->mask_gc : (gtk_gc)->gdk_gc)
268 ghid_use_mask (enum mask_mode mode
)
270 static int mask_seq_id
= 0;
272 render_priv
*priv
= gport
->render_priv
;
276 if (mode
== cur_mask
)
281 gport
->drawable
= gport
->pixmap
;
285 case HID_MASK_BEFORE
:
286 /* The HID asks not to receive this mask type, so warn if we get it */
287 g_return_if_reached ();
291 gport
->mask
= gdk_pixmap_new (0, gport
->width
, gport
->height
, 1);
292 gport
->drawable
= gport
->mask
;
296 priv
->mask_gc
= gdk_gc_new (gport
->drawable
);
297 gdk_gc_set_clip_origin (priv
->mask_gc
, 0, 0);
298 set_clip (priv
, priv
->mask_gc
);
301 gdk_gc_set_foreground (priv
->mask_gc
, &color
);
302 gdk_draw_rectangle (gport
->drawable
, priv
->mask_gc
, TRUE
, 0, 0,
303 gport
->width
, gport
->height
);
305 gdk_gc_set_foreground (priv
->mask_gc
, &color
);
312 mask_seq
= mask_seq_id
;
314 gport
->drawable
= gport
->pixmap
;
331 /* Config helper functions for when the user changes color preferences.
332 | set_special colors used in the gtkhid.
335 set_special_grid_color (void)
337 render_priv
*priv
= gport
->render_priv
;
339 if (!gport
->colormap
)
341 gport
->grid_color
.red
^= gport
->bg_color
.red
;
342 gport
->grid_color
.green
^= gport
->bg_color
.green
;
343 gport
->grid_color
.blue
^= gport
->bg_color
.blue
;
344 gdk_color_alloc (gport
->colormap
, &gport
->grid_color
);
346 gdk_gc_set_foreground (priv
->grid_gc
, &gport
->grid_color
);
350 ghid_set_special_colors (HID_Attribute
* ha
)
352 render_priv
*priv
= gport
->render_priv
;
354 if (!ha
->name
|| !ha
->value
)
356 if (!strcmp (ha
->name
, "background-color") && priv
->bg_gc
)
358 ghid_map_color_string (*(char **) ha
->value
, &gport
->bg_color
);
359 gdk_gc_set_foreground (priv
->bg_gc
, &gport
->bg_color
);
360 set_special_grid_color ();
362 else if (!strcmp (ha
->name
, "off-limit-color") && priv
->offlimits_gc
)
364 ghid_map_color_string (*(char **) ha
->value
, &gport
->offlimits_color
);
365 gdk_gc_set_foreground (priv
->offlimits_gc
, &gport
->offlimits_color
);
367 else if (!strcmp (ha
->name
, "grid-color") && priv
->grid_gc
)
369 ghid_map_color_string (*(char **) ha
->value
, &gport
->grid_color
);
370 set_special_grid_color ();
375 ghid_set_color (hidGC gc
, const char *name
)
377 gtkGC gtk_gc
= (gtkGC
)gc
;
378 static void *cache
= 0;
383 fprintf (stderr
, "%s(): name = NULL, setting to magenta\n",
388 gtk_gc
->colorname
= (char *) name
;
391 if (gport
->colormap
== 0)
392 gport
->colormap
= gtk_widget_get_colormap (gport
->top_window
);
394 if (strcmp (name
, "erase") == 0)
396 gdk_gc_set_foreground (gtk_gc
->gdk_gc
, &gport
->bg_color
);
398 else if (strcmp (name
, "drill") == 0)
400 gdk_gc_set_foreground (gtk_gc
->gdk_gc
, &gport
->offlimits_color
);
405 if (hid_cache_color (0, name
, &cval
, &cache
))
406 cc
= (ColorCache
*) cval
.ptr
;
409 cc
= (ColorCache
*) malloc (sizeof (ColorCache
));
410 memset (cc
, 0, sizeof (*cc
));
412 hid_cache_color (1, name
, &cval
, &cache
);
417 if (gdk_color_parse (name
, &cc
->color
))
418 gdk_color_alloc (gport
->colormap
, &cc
->color
);
420 gdk_color_white (gport
->colormap
, &cc
->color
);
423 if (gtk_gc
->xor_mask
)
427 cc
->xor_color
.red
= cc
->color
.red
^ gport
->bg_color
.red
;
428 cc
->xor_color
.green
= cc
->color
.green
^ gport
->bg_color
.green
;
429 cc
->xor_color
.blue
= cc
->color
.blue
^ gport
->bg_color
.blue
;
430 gdk_color_alloc (gport
->colormap
, &cc
->xor_color
);
433 gdk_gc_set_foreground (gtk_gc
->gdk_gc
, &cc
->xor_color
);
437 gdk_gc_set_foreground (gtk_gc
->gdk_gc
, &cc
->color
);
443 ghid_set_line_cap (hidGC gc
, EndCapStyle style
)
445 gtkGC gtk_gc
= (gtkGC
)gc
;
446 render_priv
*priv
= gport
->render_priv
;
452 gtk_gc
->cap
= GDK_CAP_ROUND
;
453 gtk_gc
->join
= GDK_JOIN_ROUND
;
457 gtk_gc
->cap
= GDK_CAP_PROJECTING
;
458 gtk_gc
->join
= GDK_JOIN_MITER
;
462 gdk_gc_set_line_attributes (WHICH_GC (gtk_gc
),
463 Vz (gtk_gc
->width
), GDK_LINE_SOLID
,
464 (GdkCapStyle
)gtk_gc
->cap
, (GdkJoinStyle
)gtk_gc
->join
);
468 ghid_set_line_width (hidGC gc
, Coord width
)
470 gtkGC gtk_gc
= (gtkGC
)gc
;
471 render_priv
*priv
= gport
->render_priv
;
473 gtk_gc
->width
= width
;
475 gdk_gc_set_line_attributes (WHICH_GC (gtk_gc
),
476 Vz (gtk_gc
->width
), GDK_LINE_SOLID
,
477 (GdkCapStyle
)gtk_gc
->cap
, (GdkJoinStyle
)gtk_gc
->join
);
481 ghid_set_draw_xor (hidGC gc
, int xor_mask
)
483 gtkGC gtk_gc
= (gtkGC
)gc
;
485 gtk_gc
->xor_mask
= xor_mask
;
488 gdk_gc_set_function (gtk_gc
->gdk_gc
, xor_mask
? GDK_XOR
: GDK_COPY
);
489 ghid_set_color (gc
, gtk_gc
->colorname
);
495 gtkGC gtk_gc
= (gtkGC
)gc
;
496 render_priv
*priv
= gport
->render_priv
;
497 GdkWindow
*window
= gtk_widget_get_window (gport
->top_window
);
499 if (gc
->hid
!= &ghid_hid
)
501 fprintf (stderr
, "Fatal: GC from another HID passed to GTK HID\n");
509 gtk_gc
->gdk_gc
= gdk_gc_new (window
);
510 ghid_set_color (gc
, gtk_gc
->colorname
);
511 ghid_set_line_width (gc
, gtk_gc
->width
);
512 ghid_set_line_cap (gc
, (EndCapStyle
)gtk_gc
->cap
);
513 ghid_set_draw_xor (gc
, gtk_gc
->xor_mask
);
514 gdk_gc_set_clip_origin (gtk_gc
->gdk_gc
, 0, 0);
516 if (gtk_gc
->mask_seq
!= mask_seq
)
519 gdk_gc_set_clip_mask (gtk_gc
->gdk_gc
, gport
->mask
);
521 set_clip (priv
, gtk_gc
->gdk_gc
);
522 gtk_gc
->mask_seq
= mask_seq
;
524 priv
->u_gc
= WHICH_GC (gtk_gc
);
529 ghid_draw_line (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
531 gtkGC gtk_gc
= (gtkGC
)gc
;
532 double dx1
, dy1
, dx2
, dy2
;
533 render_priv
*priv
= gport
->render_priv
;
535 dx1
= Vx ((double) x1
);
536 dy1
= Vy ((double) y1
);
537 dx2
= Vx ((double) x2
);
538 dy2
= Vy ((double) y2
);
540 if (!ClipLine (0, 0, gport
->width
, gport
->height
,
541 &dx1
, &dy1
, &dx2
, &dy2
, gtk_gc
->width
/ gport
->view
.coord_per_px
))
545 gdk_draw_line (gport
->drawable
, priv
->u_gc
, dx1
, dy1
, dx2
, dy2
);
549 ghid_draw_arc (hidGC gc
, Coord cx
, Coord cy
,
550 Coord xradius
, Coord yradius
, Angle start_angle
, Angle delta_angle
)
554 render_priv
*priv
= gport
->render_priv
;
556 w
= gport
->width
* gport
->view
.coord_per_px
;
557 h
= gport
->height
* gport
->view
.coord_per_px
;
558 radius
= (xradius
> yradius
) ? xradius
: yradius
;
559 if (SIDE_X (cx
) < gport
->view
.x0
- radius
560 || SIDE_X (cx
) > gport
->view
.x0
+ w
+ radius
561 || SIDE_Y (cy
) < gport
->view
.y0
- radius
562 || SIDE_Y (cy
) > gport
->view
.y0
+ h
+ radius
)
569 if (gport
->view
.flip_x
)
571 start_angle
= 180 - start_angle
;
572 delta_angle
= -delta_angle
;
574 if (gport
->view
.flip_y
)
576 start_angle
= -start_angle
;
577 delta_angle
= -delta_angle
;
579 /* make sure we fall in the -180 to +180 range */
580 start_angle
= NormalizeAngle (start_angle
);
581 if (start_angle
>= 180) start_angle
-= 360;
583 gdk_draw_arc (gport
->drawable
, priv
->u_gc
, 0,
584 Vx (cx
) - vrx
, Vy (cy
) - vry
,
585 vrx
* 2, vry
* 2, (start_angle
+ 180) * 64, delta_angle
* 64);
589 ghid_draw_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
591 gtkGC gtk_gc
= (gtkGC
)gc
;
593 render_priv
*priv
= gport
->render_priv
;
596 w
= gport
->width
* gport
->view
.coord_per_px
;
597 h
= gport
->height
* gport
->view
.coord_per_px
;
599 if ((SIDE_X (x1
) < gport
->view
.x0
- lw
600 && SIDE_X (x2
) < gport
->view
.x0
- lw
)
601 || (SIDE_X (x1
) > gport
->view
.x0
+ w
+ lw
602 && SIDE_X (x2
) > gport
->view
.x0
+ w
+ lw
)
603 || (SIDE_Y (y1
) < gport
->view
.y0
- lw
604 && SIDE_Y (y2
) < gport
->view
.y0
- lw
)
605 || (SIDE_Y (y1
) > gport
->view
.y0
+ h
+ lw
606 && SIDE_Y (y2
) > gport
->view
.y0
+ h
+ lw
))
628 gdk_draw_rectangle (gport
->drawable
, priv
->u_gc
, FALSE
,
629 x1
, y1
, x2
- x1
+ 1, y2
- y1
+ 1);
634 ghid_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
)
637 render_priv
*priv
= gport
->render_priv
;
639 w
= gport
->width
* gport
->view
.coord_per_px
;
640 h
= gport
->height
* gport
->view
.coord_per_px
;
641 if (SIDE_X (cx
) < gport
->view
.x0
- radius
642 || SIDE_X (cx
) > gport
->view
.x0
+ w
+ radius
643 || SIDE_Y (cy
) < gport
->view
.y0
- radius
644 || SIDE_Y (cy
) > gport
->view
.y0
+ h
+ radius
)
649 gdk_draw_arc (gport
->drawable
, priv
->u_gc
, TRUE
,
650 Vx (cx
) - vr
, Vy (cy
) - vr
, vr
* 2, vr
* 2, 0, 360 * 64);
654 ghid_fill_polygon (hidGC gc
, int n_coords
, Coord
*x
, Coord
*y
)
656 static GdkPoint
*points
= 0;
657 static int npoints
= 0;
659 render_priv
*priv
= gport
->render_priv
;
662 if (npoints
< n_coords
)
664 npoints
= n_coords
+ 1;
665 points
= (GdkPoint
*)realloc (points
, npoints
* sizeof (GdkPoint
));
667 for (i
= 0; i
< n_coords
; i
++)
669 points
[i
].x
= Vx (x
[i
]);
670 points
[i
].y
= Vy (y
[i
]);
672 gdk_draw_polygon (gport
->drawable
, priv
->u_gc
, 1, points
, n_coords
);
676 ghid_fill_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
678 gtkGC gtk_gc
= (gtkGC
)gc
;
679 gint w
, h
, lw
, xx
, yy
;
680 render_priv
*priv
= gport
->render_priv
;
683 w
= gport
->width
* gport
->view
.coord_per_px
;
684 h
= gport
->height
* gport
->view
.coord_per_px
;
686 if ((SIDE_X (x1
) < gport
->view
.x0
- lw
687 && SIDE_X (x2
) < gport
->view
.x0
- lw
)
688 || (SIDE_X (x1
) > gport
->view
.x0
+ w
+ lw
689 && SIDE_X (x2
) > gport
->view
.x0
+ w
+ lw
)
690 || (SIDE_Y (y1
) < gport
->view
.y0
- lw
691 && SIDE_Y (y2
) < gport
->view
.y0
- lw
)
692 || (SIDE_Y (y1
) > gport
->view
.y0
+ h
+ lw
693 && SIDE_Y (y2
) > gport
->view
.y0
+ h
+ lw
))
713 gdk_draw_rectangle (gport
->drawable
, priv
->u_gc
, TRUE
,
714 x1
, y1
, x2
- x1
+ 1, y2
- y1
+ 1);
718 redraw_region (GdkRectangle
*rect
)
720 int eleft
, eright
, etop
, ebottom
;
722 render_priv
*priv
= gport
->render_priv
;
729 priv
->clip_rect
= *rect
;
734 priv
->clip_rect
.x
= 0;
735 priv
->clip_rect
.y
= 0;
736 priv
->clip_rect
.width
= gport
->width
;
737 priv
->clip_rect
.height
= gport
->height
;
741 set_clip (priv
, priv
->bg_gc
);
742 set_clip (priv
, priv
->offlimits_gc
);
743 set_clip (priv
, priv
->mask_gc
);
744 set_clip (priv
, priv
->grid_gc
);
746 region
.X1
= MIN(Px(priv
->clip_rect
.x
),
747 Px(priv
->clip_rect
.x
+ priv
->clip_rect
.width
+ 1));
748 region
.Y1
= MIN(Py(priv
->clip_rect
.y
),
749 Py(priv
->clip_rect
.y
+ priv
->clip_rect
.height
+ 1));
750 region
.X2
= MAX(Px(priv
->clip_rect
.x
),
751 Px(priv
->clip_rect
.x
+ priv
->clip_rect
.width
+ 1));
752 region
.Y2
= MAX(Py(priv
->clip_rect
.y
),
753 Py(priv
->clip_rect
.y
+ priv
->clip_rect
.height
+ 1));
755 region
.X1
= MAX (0, MIN (PCB
->MaxWidth
, region
.X1
));
756 region
.X2
= MAX (0, MIN (PCB
->MaxWidth
, region
.X2
));
757 region
.Y1
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y1
));
758 region
.Y2
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y2
));
761 eright
= Vx (PCB
->MaxWidth
);
763 ebottom
= Vy (PCB
->MaxHeight
);
778 gdk_draw_rectangle (gport
->drawable
, priv
->offlimits_gc
,
779 1, 0, 0, eleft
, gport
->height
);
782 if (eright
< gport
->width
)
783 gdk_draw_rectangle (gport
->drawable
, priv
->offlimits_gc
,
784 1, eright
, 0, gport
->width
- eright
, gport
->height
);
786 eright
= gport
->width
;
788 gdk_draw_rectangle (gport
->drawable
, priv
->offlimits_gc
,
789 1, eleft
, 0, eright
- eleft
+ 1, etop
);
792 if (ebottom
< gport
->height
)
793 gdk_draw_rectangle (gport
->drawable
, priv
->offlimits_gc
,
794 1, eleft
, ebottom
, eright
- eleft
+ 1,
795 gport
->height
- ebottom
);
797 ebottom
= gport
->height
;
799 gdk_draw_rectangle (gport
->drawable
, priv
->bg_gc
, 1,
800 eleft
, etop
, eright
- eleft
+ 1, ebottom
- etop
+ 1);
802 ghid_draw_bg_image();
804 hid_expose_callback (&ghid_hid
, ®ion
, 0);
807 /* In some cases we are called with the crosshair still off */
808 if (priv
->attached_invalidate_depth
== 0)
809 DrawAttached (priv
->crosshair_gc
);
811 /* In some cases we are called with the mark still off */
812 if (priv
->mark_invalidate_depth
== 0)
813 DrawMark (priv
->crosshair_gc
);
815 draw_lead_user (priv
);
819 /* Rest the clip for bg_gc, as it is used outside this function */
820 gdk_gc_set_clip_mask (priv
->bg_gc
, NULL
);
824 ghid_invalidate_lr (int left
, int right
, int top
, int bottom
)
826 int dleft
, dright
, dtop
, dbottom
;
827 int minx
, maxx
, miny
, maxy
;
833 dbottom
= Vy (bottom
);
835 minx
= MIN (dleft
, dright
);
836 maxx
= MAX (dleft
, dright
);
837 miny
= MIN (dtop
, dbottom
);
838 maxy
= MAX (dtop
, dbottom
);
842 rect
.width
= maxx
- minx
;
843 rect
.height
= maxy
- miny
;
845 redraw_region (&rect
);
846 ghid_screen_update ();
851 ghid_invalidate_all ()
853 redraw_region (NULL
);
854 ghid_screen_update ();
858 ghid_notify_crosshair_change (bool changes_complete
)
860 render_priv
*priv
= gport
->render_priv
;
862 /* We sometimes get called before the GUI is up */
863 if (gport
->drawing_area
== NULL
)
866 if (changes_complete
)
867 priv
->attached_invalidate_depth
--;
869 if (priv
->attached_invalidate_depth
< 0)
871 priv
->attached_invalidate_depth
= 0;
872 /* A mismatch of changes_complete == false and == true notifications
873 * is not expected to occur, but we will try to handle it gracefully.
874 * As we know the crosshair will have been shown already, we must
875 * repaint the entire view to be sure not to leave an artaefact.
877 ghid_invalidate_all ();
881 if (priv
->attached_invalidate_depth
== 0)
882 DrawAttached (priv
->crosshair_gc
);
884 if (!changes_complete
)
886 priv
->attached_invalidate_depth
++;
888 else if (gport
->drawing_area
!= NULL
)
890 /* Queue a GTK expose when changes are complete */
891 ghid_draw_area_update (gport
, NULL
);
896 ghid_notify_mark_change (bool changes_complete
)
898 render_priv
*priv
= gport
->render_priv
;
900 /* We sometimes get called before the GUI is up */
901 if (gport
->drawing_area
== NULL
)
904 if (changes_complete
)
905 priv
->mark_invalidate_depth
--;
907 if (priv
->mark_invalidate_depth
< 0)
909 priv
->mark_invalidate_depth
= 0;
910 /* A mismatch of changes_complete == false and == true notifications
911 * is not expected to occur, but we will try to handle it gracefully.
912 * As we know the mark will have been shown already, we must
913 * repaint the entire view to be sure not to leave an artaefact.
915 ghid_invalidate_all ();
919 if (priv
->mark_invalidate_depth
== 0)
920 DrawMark (priv
->crosshair_gc
);
922 if (!changes_complete
)
924 priv
->mark_invalidate_depth
++;
926 else if (gport
->drawing_area
!= NULL
)
928 /* Queue a GTK expose when changes are complete */
929 ghid_draw_area_update (gport
, NULL
);
934 draw_right_cross (GdkGC
*xor_gc
, gint x
, gint y
)
936 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
938 gdk_draw_line (window
, xor_gc
, x
, 0, x
, gport
->height
);
939 gdk_draw_line (window
, xor_gc
, 0, y
, gport
->width
, y
);
943 draw_slanted_cross (GdkGC
*xor_gc
, gint x
, gint y
)
945 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
948 x0
= x
+ (gport
->height
- y
);
949 x0
= MAX(0, MIN (x0
, gport
->width
));
951 x1
= MAX(0, MIN (x1
, gport
->width
));
952 y0
= y
+ (gport
->width
- x
);
953 y0
= MAX(0, MIN (y0
, gport
->height
));
955 y1
= MAX(0, MIN (y1
, gport
->height
));
956 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
958 x0
= x
- (gport
->height
- y
);
959 x0
= MAX(0, MIN (x0
, gport
->width
));
961 x1
= MAX(0, MIN (x1
, gport
->width
));
963 y0
= MAX(0, MIN (y0
, gport
->height
));
964 y1
= y
- (gport
->width
- x
);
965 y1
= MAX(0, MIN (y1
, gport
->height
));
966 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
970 draw_dozen_cross (GdkGC
*xor_gc
, gint x
, gint y
)
972 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
974 gdouble tan60
= sqrt (3);
976 x0
= x
+ (gport
->height
- y
) / tan60
;
977 x0
= MAX(0, MIN (x0
, gport
->width
));
979 x1
= MAX(0, MIN (x1
, gport
->width
));
980 y0
= y
+ (gport
->width
- x
) * tan60
;
981 y0
= MAX(0, MIN (y0
, gport
->height
));
983 y1
= MAX(0, MIN (y1
, gport
->height
));
984 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
986 x0
= x
+ (gport
->height
- y
) * tan60
;
987 x0
= MAX(0, MIN (x0
, gport
->width
));
989 x1
= MAX(0, MIN (x1
, gport
->width
));
990 y0
= y
+ (gport
->width
- x
) / tan60
;
991 y0
= MAX(0, MIN (y0
, gport
->height
));
993 y1
= MAX(0, MIN (y1
, gport
->height
));
994 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
996 x0
= x
- (gport
->height
- y
) / tan60
;
997 x0
= MAX(0, MIN (x0
, gport
->width
));
999 x1
= MAX(0, MIN (x1
, gport
->width
));
1001 y0
= MAX(0, MIN (y0
, gport
->height
));
1002 y1
= y
- (gport
->width
- x
) * tan60
;
1003 y1
= MAX(0, MIN (y1
, gport
->height
));
1004 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
1006 x0
= x
- (gport
->height
- y
) * tan60
;
1007 x0
= MAX(0, MIN (x0
, gport
->width
));
1009 x1
= MAX(0, MIN (x1
, gport
->width
));
1011 y0
= MAX(0, MIN (y0
, gport
->height
));
1012 y1
= y
- (gport
->width
- x
) / tan60
;
1013 y1
= MAX(0, MIN (y1
, gport
->height
));
1014 gdk_draw_line (window
, xor_gc
, x0
, y0
, x1
, y1
);
1018 draw_crosshair (render_priv
*priv
)
1020 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
1021 GtkStyle
*style
= gtk_widget_get_style (gport
->drawing_area
);
1023 static GdkGC
*xor_gc
;
1024 static GdkColor cross_color
;
1026 if (gport
->crosshair_x
< 0 || ghidgui
->creating
|| !gport
->has_entered
)
1031 xor_gc
= gdk_gc_new (window
);
1032 gdk_gc_copy (xor_gc
, style
->white_gc
);
1033 gdk_gc_set_function (xor_gc
, GDK_XOR
);
1034 gdk_gc_set_clip_origin (xor_gc
, 0, 0);
1035 set_clip (priv
, xor_gc
);
1036 /* FIXME: when CrossColor changed from config */
1037 ghid_map_color_string (Settings
.CrossColor
, &cross_color
);
1040 gdk_gc_set_foreground (xor_gc
, &cross_color
);
1042 x
= DRAW_X (gport
->crosshair_x
);
1043 y
= DRAW_Y (gport
->crosshair_y
);
1045 draw_right_cross (xor_gc
, x
, y
);
1046 if (Crosshair
.shape
== Union_Jack_Crosshair_Shape
)
1047 draw_slanted_cross (xor_gc
, x
, y
);
1048 if (Crosshair
.shape
== Dozen_Crosshair_Shape
)
1049 draw_dozen_cross (xor_gc
, x
, y
);
1053 ghid_init_renderer (int *argc
, char ***argv
, GHidPort
*port
)
1055 /* Init any GC's required */
1056 port
->render_priv
= g_new0 (render_priv
, 1);
1057 port
->render_priv
->crosshair_gc
= hid_draw_make_gc (&ghid_graphics
);
1061 ghid_shutdown_renderer (GHidPort
*port
)
1063 render_priv
*priv
= port
->render_priv
;
1065 hid_draw_destroy_gc (priv
->crosshair_gc
);
1066 ghid_cancel_lead_user ();
1067 g_free (port
->render_priv
);
1068 port
->render_priv
= NULL
;
1072 ghid_init_drawing_widget (GtkWidget
*widget
, GHidPort
*port
)
1077 ghid_drawing_area_configure_hook (GHidPort
*port
)
1079 static int done_once
= 0;
1080 render_priv
*priv
= port
->render_priv
;
1084 priv
->bg_gc
= gdk_gc_new (port
->drawable
);
1085 gdk_gc_set_foreground (priv
->bg_gc
, &port
->bg_color
);
1086 gdk_gc_set_clip_origin (priv
->bg_gc
, 0, 0);
1088 priv
->offlimits_gc
= gdk_gc_new (port
->drawable
);
1089 gdk_gc_set_foreground (priv
->offlimits_gc
, &port
->offlimits_color
);
1090 gdk_gc_set_clip_origin (priv
->offlimits_gc
, 0, 0);
1096 g_object_unref (port
->mask
);
1097 port
->mask
= gdk_pixmap_new (0, port
->width
, port
->height
, 1);
1102 ghid_screen_update (void)
1104 render_priv
*priv
= gport
->render_priv
;
1105 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
1107 if (gport
->pixmap
== NULL
)
1110 gdk_draw_drawable (window
, priv
->bg_gc
, gport
->pixmap
,
1111 0, 0, 0, 0, gport
->width
, gport
->height
);
1112 draw_crosshair (priv
);
1116 ghid_drawing_area_expose_cb (GtkWidget
*widget
,
1120 render_priv
*priv
= port
->render_priv
;
1121 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
1123 gdk_draw_drawable (window
, priv
->bg_gc
, port
->pixmap
,
1124 ev
->area
.x
, ev
->area
.y
, ev
->area
.x
, ev
->area
.y
,
1125 ev
->area
.width
, ev
->area
.height
);
1126 draw_crosshair (priv
);
1131 ghid_port_drawing_realize_cb (GtkWidget
*widget
, gpointer data
)
1136 ghid_pinout_preview_expose (GtkWidget
*widget
,
1139 GhidPinoutPreview
*pinout
= GHID_PINOUT_PREVIEW (widget
);
1140 GdkWindow
*window
= gtk_widget_get_window (widget
);
1141 GdkDrawable
*save_drawable
;
1142 GtkAllocation allocation
;
1143 view_data save_view
;
1144 int save_width
, save_height
;
1145 Coord save_max_width
;
1146 Coord save_max_height
;
1148 render_priv
*priv
= gport
->render_priv
;
1150 /* Setup drawable and zoom factor for drawing routines
1152 save_drawable
= gport
->drawable
;
1153 save_view
= gport
->view
;
1154 save_width
= gport
->width
;
1155 save_height
= gport
->height
;
1156 save_max_width
= PCB
->MaxWidth
;
1157 save_max_height
= PCB
->MaxHeight
;
1159 gtk_widget_get_allocation (widget
, &allocation
);
1160 xz
= (double) pinout
->x_max
/ allocation
.width
;
1161 yz
= (double) pinout
->y_max
/ allocation
.height
;
1163 gport
->view
.coord_per_px
= xz
;
1165 gport
->view
.coord_per_px
= yz
;
1167 gport
->drawable
= window
;
1168 gport
->width
= allocation
.width
;
1169 gport
->height
= allocation
.height
;
1170 gport
->view
.width
= allocation
.width
* gport
->view
.coord_per_px
;
1171 gport
->view
.height
= allocation
.height
* gport
->view
.coord_per_px
;
1172 gport
->view
.x0
= (pinout
->x_max
- gport
->view
.width
) / 2;
1173 gport
->view
.y0
= (pinout
->y_max
- gport
->view
.height
) / 2;
1174 PCB
->MaxWidth
= pinout
->x_max
;
1175 PCB
->MaxHeight
= pinout
->y_max
;
1177 /* clear background */
1178 gdk_draw_rectangle (window
, priv
->bg_gc
, TRUE
,
1179 0, 0, allocation
.width
, allocation
.height
);
1181 /* call the drawing routine */
1182 hid_expose_callback (&ghid_hid
, NULL
, pinout
->element
);
1184 gport
->drawable
= save_drawable
;
1185 gport
->view
= save_view
;
1186 gport
->width
= save_width
;
1187 gport
->height
= save_height
;
1188 PCB
->MaxWidth
= save_max_width
;
1189 PCB
->MaxHeight
= save_max_height
;
1195 ghid_render_pixmap (int cx
, int cy
, double zoom
, int width
, int height
, int depth
)
1198 GdkDrawable
*save_drawable
;
1199 view_data save_view
;
1200 int save_width
, save_height
;
1202 render_priv
*priv
= gport
->render_priv
;
1204 save_drawable
= gport
->drawable
;
1205 save_view
= gport
->view
;
1206 save_width
= gport
->width
;
1207 save_height
= gport
->height
;
1209 pixmap
= gdk_pixmap_new (NULL
, width
, height
, depth
);
1211 /* Setup drawable and zoom factor for drawing routines
1214 gport
->drawable
= pixmap
;
1215 gport
->view
.coord_per_px
= zoom
;
1216 gport
->width
= width
;
1217 gport
->height
= height
;
1218 gport
->view
.width
= width
* gport
->view
.coord_per_px
;
1219 gport
->view
.height
= height
* gport
->view
.coord_per_px
;
1220 gport
->view
.x0
= gport
->view
.flip_x
? PCB
->MaxWidth
- cx
: cx
;
1221 gport
->view
.x0
-= gport
->view
.height
/ 2;
1222 gport
->view
.y0
= gport
->view
.flip_y
? PCB
->MaxHeight
- cy
: cy
;
1223 gport
->view
.y0
-= gport
->view
.width
/ 2;
1225 /* clear background */
1226 gdk_draw_rectangle (pixmap
, priv
->bg_gc
, TRUE
, 0, 0, width
, height
);
1228 /* call the drawing routine */
1229 region
.X1
= MIN(Px(0), Px(gport
->width
+ 1));
1230 region
.Y1
= MIN(Py(0), Py(gport
->height
+ 1));
1231 region
.X2
= MAX(Px(0), Px(gport
->width
+ 1));
1232 region
.Y2
= MAX(Py(0), Py(gport
->height
+ 1));
1234 region
.X1
= MAX (0, MIN (PCB
->MaxWidth
, region
.X1
));
1235 region
.X2
= MAX (0, MIN (PCB
->MaxWidth
, region
.X2
));
1236 region
.Y1
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y1
));
1237 region
.Y2
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y2
));
1239 hid_expose_callback (&ghid_hid
, ®ion
, NULL
);
1241 gport
->drawable
= save_drawable
;
1242 gport
->view
= save_view
;
1243 gport
->width
= save_width
;
1244 gport
->height
= save_height
;
1250 ghid_request_debug_draw (void)
1252 /* No special setup requirements, drawing goes into
1253 * the backing pixmap. */
1254 return ghid_hid
.graphics
;
1258 ghid_flush_debug_draw (void)
1260 ghid_screen_update ();
1265 ghid_finish_debug_draw (void)
1267 ghid_flush_debug_draw ();
1268 /* No special tear down requirements
1273 ghid_event_to_pcb_coords (int event_x
, int event_y
, Coord
*pcb_x
, Coord
*pcb_y
)
1275 *pcb_x
= EVENT_TO_PCB_X (event_x
);
1276 *pcb_y
= EVENT_TO_PCB_Y (event_y
);
1282 ghid_pcb_to_event_coords (Coord pcb_x
, Coord pcb_y
, int *event_x
, int *event_y
)
1284 *event_x
= DRAW_X (pcb_x
);
1285 *event_y
= DRAW_Y (pcb_y
);
1291 #define LEAD_USER_WIDTH 0.2 /* millimeters */
1292 #define LEAD_USER_PERIOD (1000 / 5) /* 5fps (in ms) */
1293 #define LEAD_USER_VELOCITY 3. /* millimeters per second */
1294 #define LEAD_USER_ARC_COUNT 3
1295 #define LEAD_USER_ARC_SEPARATION 3. /* millimeters */
1296 #define LEAD_USER_INITIAL_RADIUS 10. /* millimetres */
1297 #define LEAD_USER_COLOR_R 1.
1298 #define LEAD_USER_COLOR_G 1.
1299 #define LEAD_USER_COLOR_B 0.
1302 draw_lead_user (render_priv
*priv
)
1304 GdkWindow
*window
= gtk_widget_get_window (gport
->drawing_area
);
1305 GtkStyle
*style
= gtk_widget_get_style (gport
->drawing_area
);
1307 Coord radius
= priv
->lead_user_radius
;
1308 Coord width
= MM_TO_COORD (LEAD_USER_WIDTH
);
1309 Coord separation
= MM_TO_COORD (LEAD_USER_ARC_SEPARATION
);
1310 static GdkGC
*lead_gc
= NULL
;
1311 GdkColor lead_color
;
1313 if (!priv
->lead_user
)
1316 if (lead_gc
== NULL
)
1318 lead_gc
= gdk_gc_new (window
);
1319 gdk_gc_copy (lead_gc
, style
->white_gc
);
1320 gdk_gc_set_function (lead_gc
, GDK_XOR
);
1321 gdk_gc_set_clip_origin (lead_gc
, 0, 0);
1322 lead_color
.pixel
= 0;
1323 lead_color
.red
= (int)(65535. * LEAD_USER_COLOR_R
);
1324 lead_color
.green
= (int)(65535. * LEAD_USER_COLOR_G
);
1325 lead_color
.blue
= (int)(65535. * LEAD_USER_COLOR_B
);
1326 gdk_color_alloc (gport
->colormap
, &lead_color
);
1327 gdk_gc_set_foreground (lead_gc
, &lead_color
);
1330 set_clip (priv
, lead_gc
);
1331 gdk_gc_set_line_attributes (lead_gc
, Vz (width
),
1332 GDK_LINE_SOLID
, GDK_CAP_BUTT
, GDK_JOIN_MITER
);
1334 /* arcs at the approrpriate radii */
1336 for (i
= 0; i
< LEAD_USER_ARC_COUNT
; i
++, radius
-= separation
)
1339 radius
+= MM_TO_COORD (LEAD_USER_INITIAL_RADIUS
);
1341 /* Draw an arc at radius */
1342 gdk_draw_arc (gport
->drawable
, lead_gc
, FALSE
,
1343 Vx (priv
->lead_user_x
- radius
),
1344 Vy (priv
->lead_user_y
- radius
),
1345 Vz (2. * radius
), Vz (2. * radius
),
1351 lead_user_cb (gpointer data
)
1353 render_priv
*priv
= data
;
1355 double elapsed_time
;
1357 /* Queue a redraw */
1358 ghid_invalidate_all ();
1361 elapsed_time
= g_timer_elapsed (priv
->lead_user_timer
, NULL
);
1362 g_timer_start (priv
->lead_user_timer
);
1364 step
= MM_TO_COORD (LEAD_USER_VELOCITY
* elapsed_time
);
1365 if (priv
->lead_user_radius
> step
)
1366 priv
->lead_user_radius
-= step
;
1368 priv
->lead_user_radius
= MM_TO_COORD (LEAD_USER_INITIAL_RADIUS
);
1374 ghid_lead_user_to_location (Coord x
, Coord y
)
1376 render_priv
*priv
= gport
->render_priv
;
1378 ghid_cancel_lead_user ();
1380 priv
->lead_user
= true;
1381 priv
->lead_user_x
= x
;
1382 priv
->lead_user_y
= y
;
1383 priv
->lead_user_radius
= MM_TO_COORD (LEAD_USER_INITIAL_RADIUS
);
1384 priv
->lead_user_timeout
= g_timeout_add (LEAD_USER_PERIOD
, lead_user_cb
, priv
);
1385 priv
->lead_user_timer
= g_timer_new ();
1389 ghid_cancel_lead_user (void)
1391 render_priv
*priv
= gport
->render_priv
;
1393 if (priv
->lead_user_timeout
)
1394 g_source_remove (priv
->lead_user_timeout
);
1396 if (priv
->lead_user_timer
)
1397 g_timer_destroy (priv
->lead_user_timer
);
1399 if (priv
->lead_user
)
1400 ghid_invalidate_all ();
1402 priv
->lead_user_timeout
= 0;
1403 priv
->lead_user_timer
= NULL
;
1404 priv
->lead_user
= false;