pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00034 #ifdef HAVE_CONFIG_H 00035 #include "config.h" 00036 #endif 00037 00038 #include <stdio.h> 00039 00040 #include "crosshair.h" 00041 #include "clip.h" 00042 #include "../hidint.h" 00043 #include "gui.h" 00044 #include "hid/common/draw_helpers.h" 00045 00046 #ifdef HAVE_LIBDMALLOC 00047 #include <dmalloc.h> 00048 #endif 00049 00050 extern HID ghid_hid; 00051 extern HID_DRAW ghid_graphics; 00052 00053 /* Sets priv->u_gc to the "right" GC to use (wrt mask or window) 00054 */ 00055 #define USE_GC(gc) if (!use_gc(gc)) return 00056 00057 static enum mask_mode cur_mask = HID_MASK_OFF; 00058 static int mask_seq = 0; 00059 00060 typedef struct render_priv { 00061 GdkGC *bg_gc; 00062 GdkGC *offlimits_gc; 00063 GdkGC *mask_gc; 00064 GdkGC *u_gc; 00065 GdkGC *grid_gc; 00066 bool clip; 00067 GdkRectangle clip_rect; 00068 int attached_invalidate_depth; 00069 int mark_invalidate_depth; 00070 00071 /* Feature for leading the user to a particular location */ 00072 guint lead_user_timeout; 00073 GTimer *lead_user_timer; 00074 bool lead_user; 00075 Coord lead_user_radius; 00076 Coord lead_user_x; 00077 Coord lead_user_y; 00078 00079 hidGC crosshair_gc; 00080 } render_priv; 00081 00082 00083 typedef struct hid_gc_struct 00084 { 00085 HID *me_pointer; 00086 GdkGC *gc; 00087 00088 gchar *colorname; 00089 Coord width; 00090 gint cap, join; 00091 gchar xor_mask; 00092 gint mask_seq; 00093 } 00094 hid_gc_struct; 00095 00096 00097 static void draw_lead_user (render_priv *priv); 00098 00099 00100 int 00101 ghid_set_layer (const char *name, int group, int empty) 00102 { 00103 int idx = group; 00104 if (idx >= 0 && idx < max_group) 00105 { 00106 int n = PCB->LayerGroups.Number[group]; 00107 for (idx = 0; idx < n-1; idx ++) 00108 { 00109 int ni = PCB->LayerGroups.Entries[group][idx]; 00110 if (ni >= 0 && ni < max_copper_layer + SILK_LAYER 00111 && PCB->Data->Layer[ni].On) 00112 break; 00113 } 00114 idx = PCB->LayerGroups.Entries[group][idx]; 00115 } 00116 00117 if (idx >= 0 && idx < max_copper_layer + SILK_LAYER) 00118 return /*pinout ? 1 : */ PCB->Data->Layer[idx].On; 00119 if (idx < 0) 00120 { 00121 switch (SL_TYPE (idx)) 00122 { 00123 case SL_INVISIBLE: 00124 return /* pinout ? 0 : */ PCB->InvisibleObjectsOn; 00125 case SL_MASK: 00126 if (SL_MYSIDE (idx) /*&& !pinout */ ) 00127 return TEST_FLAG (SHOWMASKFLAG, PCB); 00128 return 0; 00129 case SL_SILK: 00130 if (SL_MYSIDE (idx) /*|| pinout */ ) 00131 return PCB->ElementOn; 00132 return 0; 00133 case SL_ASSY: 00134 return 0; 00135 case SL_PDRILL: 00136 case SL_UDRILL: 00137 return 1; 00138 case SL_RATS: 00139 return PCB->RatOn; 00140 } 00141 } 00142 return 0; 00143 } 00144 00145 void 00146 ghid_destroy_gc (hidGC gc) 00147 { 00148 if (gc->gc) 00149 g_object_unref (gc->gc); 00150 g_free (gc); 00151 } 00152 00153 hidGC 00154 ghid_make_gc (void) 00155 { 00156 hidGC rv; 00157 00158 rv = g_new0 (hid_gc_struct, 1); 00159 rv->me_pointer = &ghid_hid; 00160 rv->colorname = Settings.BackgroundColor; 00161 return rv; 00162 } 00163 00170 static void 00171 set_clip (render_priv *priv, GdkGC *gc) 00172 { 00173 if (gc == NULL) 00174 return; 00175 00176 if (priv->clip) 00177 gdk_gc_set_clip_rectangle (gc, &priv->clip_rect); 00178 else 00179 gdk_gc_set_clip_mask (gc, NULL); 00180 } 00181 00185 void 00186 ghid_draw_grid (BoxType * region) 00187 { 00188 static GdkPoint *points = 0; 00189 static int npoints = 0; 00190 Coord x1, y1, x2, y2, x, y; 00191 int n, i; 00192 render_priv *priv = gport->render_priv; 00193 00194 if (!Settings.DrawGrid) 00195 return; /* grid hidden */ 00196 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE) 00197 return; /* zoomed out too far, points to close together */ 00198 if (!priv->grid_gc) /* create a graphics context if we don't have one */ 00199 { 00200 if (gdk_color_parse (Settings.GridColor, &gport->grid_color)) 00201 { 00202 gport->grid_color.red ^= gport->bg_color.red; 00203 gport->grid_color.green ^= gport->bg_color.green; 00204 gport->grid_color.blue ^= gport->bg_color.blue; 00205 gdk_color_alloc (gport->colormap, &gport->grid_color); 00206 } 00207 priv->grid_gc = gdk_gc_new (gport->drawable); 00208 gdk_gc_set_function (priv->grid_gc, GDK_XOR); 00209 gdk_gc_set_foreground (priv->grid_gc, &gport->grid_color); 00210 gdk_gc_set_clip_origin (priv->grid_gc, 0, 0); 00211 set_clip (priv, priv->grid_gc); 00212 } /* end if (!priv->grid_gc) */ 00213 x1 = GridFit (SIDE_X (gport->view.x0), PCB->Grid, PCB->GridOffsetX); 00214 y1 = GridFit (SIDE_Y (gport->view.y0), PCB->Grid, PCB->GridOffsetY); 00215 x2 = GridFit (SIDE_X (gport->view.x0 + gport->view.width - 1), 00216 PCB->Grid, PCB->GridOffsetX); 00217 y2 = GridFit (SIDE_Y (gport->view.y0 + gport->view.height - 1), 00218 PCB->Grid, PCB->GridOffsetY); 00219 if (x1 > x2) 00220 { 00221 Coord tmp = x1; 00222 x1 = x2; 00223 x2 = tmp; 00224 } 00225 if (y1 > y2) 00226 { 00227 Coord tmp = y1; 00228 y1 = y2; 00229 y2 = tmp; 00230 } 00231 00232 /* The bounding points could have been outside of the drawing area */ 00233 if (Vx (x1) < 0) x1 += PCB->Grid; 00234 if (Vy (y1) < 0) y1 += PCB->Grid; 00235 if (Vx (x2) >= gport->width) x2 -= PCB->Grid; 00236 if (Vy (y2) >= gport->height) y2 -= PCB->Grid; 00237 00238 n = (x2 - x1) / PCB->Grid + 1; /* Number of points in one row */ 00239 if (n > npoints) 00240 { /* [n]points are static, reallocate if we need more memory */ 00241 npoints = n + 10; 00242 points = (GdkPoint *)realloc (points, npoints * sizeof (GdkPoint)); 00243 } 00244 n = 0; 00245 for (x = x1; x <= x2; x += PCB->Grid) 00246 { /* compute all the x coordinates */ 00247 points[n].x = Vx (x); 00248 n++; 00249 } 00250 if (n == 0) 00251 return; 00252 for (y = y1; y <= y2; y += PCB->Grid) 00253 { /* reuse the row of points at each y */ 00254 for (i = 0; i < n; i++) points[i].y = Vy (y); 00255 /* draw all the points in a row for a given y */ 00256 gdk_draw_points (gport->drawable, priv->grid_gc, points, n); 00257 } 00258 } 00259 00260 /* ------------------------------------------------------------ */ 00261 static void 00262 ghid_draw_bg_image (void) 00263 { 00264 static GdkPixbuf *pixbuf; 00265 GdkInterpType interp_type; 00266 gint x, y, w, h, w_src, h_src; 00267 static gint w_scaled, h_scaled; 00268 render_priv *priv = gport->render_priv; 00269 00270 if (!ghidgui->bg_pixbuf) 00271 return; 00272 00273 w = PCB->MaxWidth / gport->view.coord_per_px; 00274 h = PCB->MaxHeight / gport->view.coord_per_px; 00275 x = gport->view.x0 / gport->view.coord_per_px; 00276 y = gport->view.y0 / gport->view.coord_per_px; 00277 00278 if (w_scaled != w || h_scaled != h) 00279 { 00280 if (pixbuf) 00281 g_object_unref (G_OBJECT (pixbuf)); 00282 00283 w_src = gdk_pixbuf_get_width (ghidgui->bg_pixbuf); 00284 h_src = gdk_pixbuf_get_height (ghidgui->bg_pixbuf); 00285 if (w > w_src && h > h_src) 00286 interp_type = GDK_INTERP_NEAREST; 00287 else 00288 interp_type = GDK_INTERP_BILINEAR; 00289 00290 pixbuf = 00291 gdk_pixbuf_scale_simple (ghidgui->bg_pixbuf, w, h, interp_type); 00292 w_scaled = w; 00293 h_scaled = h; 00294 } 00295 if (pixbuf) 00296 gdk_pixbuf_render_to_drawable (pixbuf, gport->drawable, priv->bg_gc, 00297 x, y, 0, 0, 00298 w - x, h - y, GDK_RGB_DITHER_NORMAL, 0, 0); 00299 } 00300 00301 #define WHICH_GC(gc) (cur_mask == HID_MASK_CLEAR ? priv->mask_gc : (gc)->gc) 00302 00303 void 00304 ghid_use_mask (enum mask_mode mode) 00305 { 00306 static int mask_seq_id = 0; 00307 GdkColor color; 00308 render_priv *priv = gport->render_priv; 00309 00310 if (!gport->pixmap) 00311 return; 00312 if (mode == cur_mask) 00313 return; 00314 switch (mode) 00315 { 00316 case HID_MASK_OFF: 00317 gport->drawable = gport->pixmap; 00318 mask_seq = 0; 00319 break; 00320 00321 case HID_MASK_BEFORE: 00322 /* The HID asks not to receive this mask type, so warn if we get it */ 00323 g_return_if_reached (); 00324 00325 case HID_MASK_CLEAR: 00326 if (!gport->mask) 00327 gport->mask = gdk_pixmap_new (0, gport->width, gport->height, 1); 00328 gport->drawable = gport->mask; 00329 mask_seq = 0; 00330 if (!priv->mask_gc) 00331 { 00332 priv->mask_gc = gdk_gc_new (gport->drawable); 00333 gdk_gc_set_clip_origin (priv->mask_gc, 0, 0); 00334 set_clip (priv, priv->mask_gc); 00335 } 00336 color.pixel = 1; 00337 gdk_gc_set_foreground (priv->mask_gc, &color); 00338 gdk_draw_rectangle (gport->drawable, priv->mask_gc, TRUE, 0, 0, 00339 gport->width, gport->height); 00340 color.pixel = 0; 00341 gdk_gc_set_foreground (priv->mask_gc, &color); 00342 break; 00343 00344 case HID_MASK_AFTER: 00345 mask_seq_id++; 00346 if (!mask_seq_id) 00347 mask_seq_id = 1; 00348 mask_seq = mask_seq_id; 00349 00350 gport->drawable = gport->pixmap; 00351 break; 00352 00353 } 00354 cur_mask = mode; 00355 } 00356 00357 00358 typedef struct 00359 { 00360 int color_set; 00361 GdkColor color; 00362 int xor_set; 00363 GdkColor xor_color; 00364 } ColorCache; 00365 00366 00367 /* Config helper functions for when the user changes color preferences. 00368 | set_special colors used in the gtkhid. 00369 */ 00370 static void 00371 set_special_grid_color (void) 00372 { 00373 render_priv *priv = gport->render_priv; 00374 00375 if (!gport->colormap) 00376 return; 00377 gport->grid_color.red ^= gport->bg_color.red; 00378 gport->grid_color.green ^= gport->bg_color.green; 00379 gport->grid_color.blue ^= gport->bg_color.blue; 00380 gdk_color_alloc (gport->colormap, &gport->grid_color); 00381 if (priv->grid_gc) 00382 gdk_gc_set_foreground (priv->grid_gc, &gport->grid_color); 00383 } 00384 00385 void 00386 ghid_set_special_colors (HID_Attribute * ha) 00387 { 00388 render_priv *priv = gport->render_priv; 00389 00390 if (!ha->name || !ha->value) 00391 return; 00392 if (!strcmp (ha->name, "background-color") && priv->bg_gc) 00393 { 00394 ghid_map_color_string (*(char **) ha->value, &gport->bg_color); 00395 gdk_gc_set_foreground (priv->bg_gc, &gport->bg_color); 00396 set_special_grid_color (); 00397 } 00398 else if (!strcmp (ha->name, "off-limit-color") && priv->offlimits_gc) 00399 { 00400 ghid_map_color_string (*(char **) ha->value, &gport->offlimits_color); 00401 gdk_gc_set_foreground (priv->offlimits_gc, &gport->offlimits_color); 00402 } 00403 else if (!strcmp (ha->name, "grid-color") && priv->grid_gc) 00404 { 00405 ghid_map_color_string (*(char **) ha->value, &gport->grid_color); 00406 set_special_grid_color (); 00407 } 00408 } 00409 00410 void 00411 ghid_set_color (hidGC gc, const char *name) 00412 { 00413 static void *cache = 0; 00414 hidval cval; 00415 00416 if (name == NULL) 00417 { 00418 fprintf (stderr, "%s(): name = NULL, setting to magenta\n", 00419 __FUNCTION__); 00420 name = "magenta"; 00421 } 00422 00423 gc->colorname = (char *) name; 00424 if (!gc->gc) 00425 return; 00426 if (gport->colormap == 0) 00427 gport->colormap = gtk_widget_get_colormap (gport->top_window); 00428 00429 if (strcmp (name, "erase") == 0) 00430 { 00431 gdk_gc_set_foreground (gc->gc, &gport->bg_color); 00432 } 00433 else if (strcmp (name, "drill") == 0) 00434 { 00435 gdk_gc_set_foreground (gc->gc, &gport->offlimits_color); 00436 } 00437 else 00438 { 00439 ColorCache *cc; 00440 if (hid_cache_color (0, name, &cval, &cache)) 00441 cc = (ColorCache *) cval.ptr; 00442 else 00443 { 00444 cc = (ColorCache *) malloc (sizeof (ColorCache)); 00445 memset (cc, 0, sizeof (*cc)); 00446 cval.ptr = cc; 00447 hid_cache_color (1, name, &cval, &cache); 00448 } 00449 00450 if (!cc->color_set) 00451 { 00452 if (gdk_color_parse (name, &cc->color)) 00453 gdk_color_alloc (gport->colormap, &cc->color); 00454 else 00455 gdk_color_white (gport->colormap, &cc->color); 00456 cc->color_set = 1; 00457 } 00458 if (gc->xor_mask) 00459 { 00460 if (!cc->xor_set) 00461 { 00462 cc->xor_color.red = cc->color.red ^ gport->bg_color.red; 00463 cc->xor_color.green = cc->color.green ^ gport->bg_color.green; 00464 cc->xor_color.blue = cc->color.blue ^ gport->bg_color.blue; 00465 gdk_color_alloc (gport->colormap, &cc->xor_color); 00466 cc->xor_set = 1; 00467 } 00468 gdk_gc_set_foreground (gc->gc, &cc->xor_color); 00469 } 00470 else 00471 { 00472 gdk_gc_set_foreground (gc->gc, &cc->color); 00473 } 00474 } 00475 } 00476 00477 void 00478 ghid_set_line_cap (hidGC gc, EndCapStyle style) 00479 { 00480 render_priv *priv = gport->render_priv; 00481 00482 switch (style) 00483 { 00484 case Trace_Cap: 00485 case Round_Cap: 00486 gc->cap = GDK_CAP_ROUND; 00487 gc->join = GDK_JOIN_ROUND; 00488 break; 00489 case Square_Cap: 00490 case Beveled_Cap: 00491 gc->cap = GDK_CAP_PROJECTING; 00492 gc->join = GDK_JOIN_MITER; 00493 break; 00494 } 00495 if (gc->gc) 00496 gdk_gc_set_line_attributes (WHICH_GC (gc), 00497 Vz (gc->width), GDK_LINE_SOLID, 00498 (GdkCapStyle)gc->cap, (GdkJoinStyle)gc->join); 00499 } 00500 00501 void 00502 ghid_set_line_width (hidGC gc, Coord width) 00503 { 00504 render_priv *priv = gport->render_priv; 00505 00506 gc->width = width; 00507 if (gc->gc) 00508 gdk_gc_set_line_attributes (WHICH_GC (gc), 00509 Vz (gc->width), GDK_LINE_SOLID, 00510 (GdkCapStyle)gc->cap, (GdkJoinStyle)gc->join); 00511 } 00512 00513 void 00514 ghid_set_draw_xor (hidGC gc, int xor_mask) 00515 { 00516 gc->xor_mask = xor_mask; 00517 if (!gc->gc) 00518 return; 00519 gdk_gc_set_function (gc->gc, xor_mask ? GDK_XOR : GDK_COPY); 00520 ghid_set_color (gc, gc->colorname); 00521 } 00522 00523 static int 00524 use_gc (hidGC gc) 00525 { 00526 render_priv *priv = gport->render_priv; 00527 GdkWindow *window = gtk_widget_get_window (gport->top_window); 00528 00529 if (gc->me_pointer != &ghid_hid) 00530 { 00531 fprintf (stderr, "Fatal: GC from another HID passed to GTK HID\n"); 00532 abort (); 00533 } 00534 00535 if (!gport->pixmap) 00536 return 0; 00537 if (!gc->gc) 00538 { 00539 gc->gc = gdk_gc_new (window); 00540 ghid_set_color (gc, gc->colorname); 00541 ghid_set_line_width (gc, gc->width); 00542 ghid_set_line_cap (gc, (EndCapStyle)gc->cap); 00543 ghid_set_draw_xor (gc, gc->xor_mask); 00544 gdk_gc_set_clip_origin (gc->gc, 0, 0); 00545 } 00546 if (gc->mask_seq != mask_seq) 00547 { 00548 if (mask_seq) 00549 gdk_gc_set_clip_mask (gc->gc, gport->mask); 00550 else 00551 set_clip (priv, gc->gc); 00552 gc->mask_seq = mask_seq; 00553 } 00554 priv->u_gc = WHICH_GC (gc); 00555 return 1; 00556 } 00557 00558 void 00559 ghid_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 00560 { 00561 double dx1, dy1, dx2, dy2; 00562 render_priv *priv = gport->render_priv; 00563 00564 dx1 = Vx ((double) x1); 00565 dy1 = Vy ((double) y1); 00566 dx2 = Vx ((double) x2); 00567 dy2 = Vy ((double) y2); 00568 00569 if (!ClipLine (0, 0, gport->width, gport->height, 00570 &dx1, &dy1, &dx2, &dy2, gc->width / gport->view.coord_per_px)) 00571 return; 00572 00573 USE_GC (gc); 00574 gdk_draw_line (gport->drawable, priv->u_gc, dx1, dy1, dx2, dy2); 00575 } 00576 00577 void 00578 ghid_draw_arc (hidGC gc, Coord cx, Coord cy, 00579 Coord xradius, Coord yradius, Angle start_angle, Angle delta_angle) 00580 { 00581 gint vrx, vry; 00582 gint w, h, radius; 00583 render_priv *priv = gport->render_priv; 00584 00585 w = gport->width * gport->view.coord_per_px; 00586 h = gport->height * gport->view.coord_per_px; 00587 radius = (xradius > yradius) ? xradius : yradius; 00588 if (SIDE_X (cx) < gport->view.x0 - radius 00589 || SIDE_X (cx) > gport->view.x0 + w + radius 00590 || SIDE_Y (cy) < gport->view.y0 - radius 00591 || SIDE_Y (cy) > gport->view.y0 + h + radius) 00592 return; 00593 00594 USE_GC (gc); 00595 vrx = Vz (xradius); 00596 vry = Vz (yradius); 00597 00598 if (gport->view.flip_x) 00599 { 00600 start_angle = 180 - start_angle; 00601 delta_angle = -delta_angle; 00602 } 00603 if (gport->view.flip_y) 00604 { 00605 start_angle = -start_angle; 00606 delta_angle = -delta_angle; 00607 } 00608 /* make sure we fall in the -180 to +180 range */ 00609 start_angle = NormalizeAngle (start_angle); 00610 if (start_angle >= 180) start_angle -= 360; 00611 00612 gdk_draw_arc (gport->drawable, priv->u_gc, 0, 00613 Vx (cx) - vrx, Vy (cy) - vry, 00614 vrx * 2, vry * 2, (start_angle + 180) * 64, delta_angle * 64); 00615 } 00616 00617 void 00618 ghid_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 00619 { 00620 gint w, h, lw; 00621 render_priv *priv = gport->render_priv; 00622 00623 lw = gc->width; 00624 w = gport->width * gport->view.coord_per_px; 00625 h = gport->height * gport->view.coord_per_px; 00626 00627 if ((SIDE_X (x1) < gport->view.x0 - lw 00628 && SIDE_X (x2) < gport->view.x0 - lw) 00629 || (SIDE_X (x1) > gport->view.x0 + w + lw 00630 && SIDE_X (x2) > gport->view.x0 + w + lw) 00631 || (SIDE_Y (y1) < gport->view.y0 - lw 00632 && SIDE_Y (y2) < gport->view.y0 - lw) 00633 || (SIDE_Y (y1) > gport->view.y0 + h + lw 00634 && SIDE_Y (y2) > gport->view.y0 + h + lw)) 00635 return; 00636 00637 x1 = Vx (x1); 00638 y1 = Vy (y1); 00639 x2 = Vx (x2); 00640 y2 = Vy (y2); 00641 00642 if (x1 > x2) 00643 { 00644 gint xt = x1; 00645 x1 = x2; 00646 x2 = xt; 00647 } 00648 if (y1 > y2) 00649 { 00650 gint yt = y1; 00651 y1 = y2; 00652 y2 = yt; 00653 } 00654 00655 USE_GC (gc); 00656 gdk_draw_rectangle (gport->drawable, priv->u_gc, FALSE, 00657 x1, y1, x2 - x1 + 1, y2 - y1 + 1); 00658 } 00659 00660 00661 void 00662 ghid_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius) 00663 { 00664 gint w, h, vr; 00665 render_priv *priv = gport->render_priv; 00666 00667 w = gport->width * gport->view.coord_per_px; 00668 h = gport->height * gport->view.coord_per_px; 00669 if (SIDE_X (cx) < gport->view.x0 - radius 00670 || SIDE_X (cx) > gport->view.x0 + w + radius 00671 || SIDE_Y (cy) < gport->view.y0 - radius 00672 || SIDE_Y (cy) > gport->view.y0 + h + radius) 00673 return; 00674 00675 USE_GC (gc); 00676 vr = Vz (radius); 00677 gdk_draw_arc (gport->drawable, priv->u_gc, TRUE, 00678 Vx (cx) - vr, Vy (cy) - vr, vr * 2, vr * 2, 0, 360 * 64); 00679 } 00680 00681 void 00682 ghid_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y) 00683 { 00684 static GdkPoint *points = 0; 00685 static int npoints = 0; 00686 int i; 00687 render_priv *priv = gport->render_priv; 00688 USE_GC (gc); 00689 00690 if (npoints < n_coords) 00691 { 00692 npoints = n_coords + 1; 00693 points = (GdkPoint *)realloc (points, npoints * sizeof (GdkPoint)); 00694 } 00695 for (i = 0; i < n_coords; i++) 00696 { 00697 points[i].x = Vx (x[i]); 00698 points[i].y = Vy (y[i]); 00699 } 00700 gdk_draw_polygon (gport->drawable, priv->u_gc, 1, points, n_coords); 00701 } 00702 00703 void 00704 ghid_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 00705 { 00706 gint w, h, lw, xx, yy; 00707 render_priv *priv = gport->render_priv; 00708 00709 lw = gc->width; 00710 w = gport->width * gport->view.coord_per_px; 00711 h = gport->height * gport->view.coord_per_px; 00712 00713 if ((SIDE_X (x1) < gport->view.x0 - lw 00714 && SIDE_X (x2) < gport->view.x0 - lw) 00715 || (SIDE_X (x1) > gport->view.x0 + w + lw 00716 && SIDE_X (x2) > gport->view.x0 + w + lw) 00717 || (SIDE_Y (y1) < gport->view.y0 - lw 00718 && SIDE_Y (y2) < gport->view.y0 - lw) 00719 || (SIDE_Y (y1) > gport->view.y0 + h + lw 00720 && SIDE_Y (y2) > gport->view.y0 + h + lw)) 00721 return; 00722 00723 x1 = Vx (x1); 00724 y1 = Vy (y1); 00725 x2 = Vx (x2); 00726 y2 = Vy (y2); 00727 if (x2 < x1) 00728 { 00729 xx = x1; 00730 x1 = x2; 00731 x2 = xx; 00732 } 00733 if (y2 < y1) 00734 { 00735 yy = y1; 00736 y1 = y2; 00737 y2 = yy; 00738 } 00739 USE_GC (gc); 00740 gdk_draw_rectangle (gport->drawable, priv->u_gc, TRUE, 00741 x1, y1, x2 - x1 + 1, y2 - y1 + 1); 00742 } 00743 00747 static void 00748 redraw_region (GdkRectangle *rect) 00749 { 00750 int eleft, eright, etop, ebottom; 00751 BoxType region; /* section to draw in PCB coordinates */ 00752 render_priv *priv = gport->render_priv; 00753 00754 if (!gport->pixmap) 00755 return; 00756 00757 if (rect != NULL) 00758 { /* draw the region passed as an argument */ 00759 priv->clip_rect = *rect; 00760 priv->clip = true; 00761 } 00762 else 00763 { /* specified region was null, draw the entire area */ 00764 priv->clip_rect.x = 0; 00765 priv->clip_rect.y = 0; 00766 priv->clip_rect.width = gport->width; 00767 priv->clip_rect.height = gport->height; 00768 priv->clip = false; 00769 } 00770 00771 /* set the clip to prevent changes to anything outside the region */ 00772 set_clip (priv, priv->bg_gc); 00773 set_clip (priv, priv->offlimits_gc); 00774 set_clip (priv, priv->mask_gc); 00775 set_clip (priv, priv->grid_gc); 00776 00777 /* Compute the PCB coordinates of the area to redraw */ 00778 /* Find the upper and lower corners of the drawing area */ 00779 region.X1 = MIN(Px(priv->clip_rect.x), 00780 Px(priv->clip_rect.x + priv->clip_rect.width + 1)); 00781 region.Y1 = MIN(Py(priv->clip_rect.y), 00782 Py(priv->clip_rect.y + priv->clip_rect.height + 1)); 00783 region.X2 = MAX(Px(priv->clip_rect.x), 00784 Px(priv->clip_rect.x + priv->clip_rect.width + 1)); 00785 region.Y2 = MAX(Py(priv->clip_rect.y), 00786 Py(priv->clip_rect.y + priv->clip_rect.height + 1)); 00787 00788 /* Restrict the drawing region to inside the PCB area */ 00789 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1)); 00790 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2)); 00791 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1)); 00792 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2)); 00793 00794 /* Compute the viewport coordinates of the edges of the PCB area */ 00795 eleft = Vx (0); 00796 eright = Vx (PCB->MaxWidth); 00797 etop = Vy (0); 00798 ebottom = Vy (PCB->MaxHeight); 00799 if (eleft > eright) 00800 { 00801 int tmp = eleft; 00802 eleft = eright; 00803 eright = tmp; 00804 } 00805 if (etop > ebottom) 00806 { 00807 int tmp = etop; 00808 etop = ebottom; 00809 ebottom = tmp; 00810 } 00811 00812 /* If the PCB isn't filling the entire screen, draw the dead area around it */ 00813 if (eleft > 0) /* draw dead area on the left side */ 00814 gdk_draw_rectangle (gport->drawable, priv->offlimits_gc, 00815 1, 0, 0, eleft, gport->height); 00816 else 00817 eleft = 0; 00818 if (eright < gport->width) /* draw dead area on the right side */ 00819 gdk_draw_rectangle (gport->drawable, priv->offlimits_gc, 00820 1, eright, 0, gport->width - eright, gport->height); 00821 else 00822 eright = gport->width; 00823 if (etop > 0) /* draw dead area on the top */ 00824 gdk_draw_rectangle (gport->drawable, priv->offlimits_gc, 00825 1, eleft, 0, eright - eleft + 1, etop); 00826 else 00827 etop = 0; 00828 if (ebottom < gport->height) /* draw dead area on the bottom */ 00829 gdk_draw_rectangle (gport->drawable, priv->offlimits_gc, 00830 1, eleft, ebottom, eright - eleft + 1, 00831 gport->height - ebottom); 00832 else 00833 ebottom = gport->height; 00834 00835 /* Draw the PCB background color */ 00836 gdk_draw_rectangle (gport->drawable, priv->bg_gc, 1, 00837 eleft, etop, eright - eleft + 1, ebottom - etop + 1); 00838 00839 ghid_draw_bg_image(); 00840 00841 /* Draw all of the PCB stuff, elements, traces, etc. */ 00842 hid_expose_callback (&ghid_hid, ®ion, 0); 00843 00844 ghid_graphics.draw_grid (®ion); 00845 00846 /* In some cases we are called with the crosshair still off */ 00847 if (priv->attached_invalidate_depth == 0) 00848 DrawAttached (priv->crosshair_gc); 00849 00850 /* In some cases we are called with the mark still off */ 00851 if (priv->mark_invalidate_depth == 0) 00852 DrawMark (priv->crosshair_gc); 00853 00854 draw_lead_user (priv); 00855 00856 /* Turn clipping off */ 00857 priv->clip = false; 00858 00859 /* Reset the clip for bg_gc, as it is used outside this function */ 00860 gdk_gc_set_clip_mask (priv->bg_gc, NULL); 00861 } 00862 00863 void 00864 ghid_invalidate_lr (Coord left, Coord right, Coord top, Coord bottom) 00865 { 00866 Coord dleft, dright, dtop, dbottom; 00867 Coord minx, maxx, miny, maxy; 00868 GdkRectangle rect; 00869 00870 dleft = Vx (left); 00871 dright = Vx (right); 00872 dtop = Vy (top); 00873 dbottom = Vy (bottom); 00874 00875 minx = MIN (dleft, dright); 00876 maxx = MAX (dleft, dright); 00877 miny = MIN (dtop, dbottom); 00878 maxy = MAX (dtop, dbottom); 00879 00880 rect.x = minx; 00881 rect.y = miny; 00882 rect.width = maxx - minx; 00883 rect.height = maxy - miny; 00884 00885 redraw_region (&rect); 00886 ghid_screen_update (); 00887 } 00888 00889 00890 void 00891 ghid_invalidate_all () 00892 { 00893 redraw_region (NULL); 00894 ghid_screen_update (); 00895 } 00896 00897 void 00898 ghid_notify_crosshair_change (bool changes_complete) 00899 { 00900 render_priv *priv = gport->render_priv; 00901 00902 /* We sometimes get called before the GUI is up */ 00903 if (gport->drawing_area == NULL) 00904 return; 00905 00906 if (changes_complete) 00907 priv->attached_invalidate_depth --; 00908 00909 if (priv->attached_invalidate_depth < 0) 00910 { 00911 priv->attached_invalidate_depth = 0; 00912 /* A mismatch of changes_complete == false and == true notifications 00913 * is not expected to occur, but we will try to handle it gracefully. 00914 * As we know the crosshair will have been shown already, we must 00915 * repaint the entire view to be sure not to leave an artaefact. 00916 */ 00917 ghid_invalidate_all (); 00918 return; 00919 } 00920 00921 if (priv->attached_invalidate_depth == 0) 00922 DrawAttached (priv->crosshair_gc); 00923 00924 if (!changes_complete) 00925 { 00926 priv->attached_invalidate_depth ++; 00927 } 00928 else if (gport->drawing_area != NULL) 00929 { 00930 /* Queue a GTK expose when changes are complete */ 00931 ghid_draw_area_update (gport, NULL); 00932 } 00933 } 00934 00935 void 00936 ghid_notify_mark_change (bool changes_complete) 00937 { 00938 render_priv *priv = gport->render_priv; 00939 00940 /* We sometimes get called before the GUI is up */ 00941 if (gport->drawing_area == NULL) 00942 return; 00943 00944 if (changes_complete) 00945 priv->mark_invalidate_depth --; 00946 00947 if (priv->mark_invalidate_depth < 0) 00948 { 00949 priv->mark_invalidate_depth = 0; 00950 /* A mismatch of changes_complete == false and == true notifications 00951 * is not expected to occur, but we will try to handle it gracefully. 00952 * As we know the mark will have been shown already, we must 00953 * repaint the entire view to be sure not to leave an artaefact. 00954 */ 00955 ghid_invalidate_all (); 00956 return; 00957 } 00958 00959 if (priv->mark_invalidate_depth == 0) 00960 DrawMark (priv->crosshair_gc); 00961 00962 if (!changes_complete) 00963 { 00964 priv->mark_invalidate_depth ++; 00965 } 00966 else if (gport->drawing_area != NULL) 00967 { 00968 /* Queue a GTK expose when changes are complete */ 00969 ghid_draw_area_update (gport, NULL); 00970 } 00971 } 00972 00973 static void 00974 draw_right_cross (GdkGC *xor_gc, gint x, gint y) 00975 { 00976 GdkWindow *window = gtk_widget_get_window (gport->drawing_area); 00977 00978 gdk_draw_line (window, xor_gc, x, 0, x, gport->height); 00979 gdk_draw_line (window, xor_gc, 0, y, gport->width, y); 00980 } 00981 00982 static void 00983 draw_slanted_cross (GdkGC *xor_gc, gint x, gint y) 00984 { 00985 GdkWindow *window = gtk_widget_get_window (gport->drawing_area); 00986 gint x0, y0, x1, y1; 00987 00988 x0 = x + (gport->height - y); 00989 x0 = MAX(0, MIN (x0, gport->width)); 00990 x1 = x - y; 00991 x1 = MAX(0, MIN (x1, gport->width)); 00992 y0 = y + (gport->width - x); 00993 y0 = MAX(0, MIN (y0, gport->height)); 00994 y1 = y - x; 00995 y1 = MAX(0, MIN (y1, gport->height)); 00996 gdk_draw_line (window, xor_gc, x0, y0, x1, y1); 00997 00998 x0 = x - (gport->height - y); 00999 x0 = MAX(0, MIN (x0, gport->width)); 01000 x1 = x + y; 01001 x1 = MAX(0, MIN (x1, gport->width)); 01002 y0 = y + x; 01003 y0 = MAX(0, MIN (y0, gport->height)); 01004 y1 = y - (gport->width - x); 01005 y1 = MAX(0, MIN (y1, gport->height)); 01006 gdk_draw_line (window, xor_gc, x0, y0, x1, y1); 01007 } 01008 01009 static void 01010 draw_dozen_cross (GdkGC *xor_gc, gint x, gint y) 01011 { 01012 GdkWindow *window = gtk_widget_get_window (gport->drawing_area); 01013 gint x0, y0, x1, y1; 01014 gdouble tan60 = sqrt (3); 01015 01016 x0 = x + (gport->height - y) / tan60; 01017 x0 = MAX(0, MIN (x0, gport->width)); 01018 x1 = x - y / tan60; 01019 x1 = MAX(0, MIN (x1, gport->width)); 01020 y0 = y + (gport->width - x) * tan60; 01021 y0 = MAX(0, MIN (y0, gport->height)); 01022 y1 = y - x * tan60; 01023 y1 = MAX(0, MIN (y1, gport->height)); 01024 gdk_draw_line (window, xor_gc, x0, y0, x1, y1); 01025 01026 x0 = x + (gport->height - y) * tan60; 01027 x0 = MAX(0, MIN (x0, gport->width)); 01028 x1 = x - y * tan60; 01029 x1 = MAX(0, MIN (x1, gport->width)); 01030 y0 = y + (gport->width - x) / tan60; 01031 y0 = MAX(0, MIN (y0, gport->height)); 01032 y1 = y - x / tan60; 01033 y1 = MAX(0, MIN (y1, gport->height)); 01034 gdk_draw_line (window, xor_gc, x0, y0, x1, y1); 01035 01036 x0 = x - (gport->height - y) / tan60; 01037 x0 = MAX(0, MIN (x0, gport->width)); 01038 x1 = x + y / tan60; 01039 x1 = MAX(0, MIN (x1, gport->width)); 01040 y0 = y + x * tan60; 01041 y0 = MAX(0, MIN (y0, gport->height)); 01042 y1 = y - (gport->width - x) * tan60; 01043 y1 = MAX(0, MIN (y1, gport->height)); 01044 gdk_draw_line (window, xor_gc, x0, y0, x1, y1); 01045 01046 x0 = x - (gport->height - y) * tan60; 01047 x0 = MAX(0, MIN (x0, gport->width)); 01048 x1 = x + y * tan60; 01049 x1 = MAX(0, MIN (x1, gport->width)); 01050 y0 = y + x / tan60; 01051 y0 = MAX(0, MIN (y0, gport->height)); 01052 y1 = y - (gport->width - x) / tan60; 01053 y1 = MAX(0, MIN (y1, gport->height)); 01054 gdk_draw_line (window, xor_gc, x0, y0, x1, y1); 01055 } 01056 01057 static void 01058 draw_crosshair (render_priv *priv) 01059 { 01060 GdkWindow *window = gtk_widget_get_window (gport->drawing_area); 01061 GtkStyle *style = gtk_widget_get_style (gport->drawing_area); 01062 gint x, y; 01063 static GdkGC *xor_gc; 01064 static GdkColor cross_color; 01065 01066 if (gport->crosshair_x < 0 || ghidgui->creating || !gport->has_entered) 01067 return; 01068 01069 if (!xor_gc) 01070 { 01071 xor_gc = gdk_gc_new (window); 01072 gdk_gc_copy (xor_gc, style->white_gc); 01073 gdk_gc_set_function (xor_gc, GDK_XOR); 01074 gdk_gc_set_clip_origin (xor_gc, 0, 0); 01075 set_clip (priv, xor_gc); 01076 /* FIXME: when CrossColor changed from config */ 01077 ghid_map_color_string (Settings.CrossColor, &cross_color); 01078 } 01079 01080 gdk_gc_set_foreground (xor_gc, &cross_color); 01081 01082 x = DRAW_X (gport->crosshair_x); 01083 y = DRAW_Y (gport->crosshair_y); 01084 01085 draw_right_cross (xor_gc, x, y); 01086 if (Crosshair.shape == Union_Jack_Crosshair_Shape) 01087 draw_slanted_cross (xor_gc, x, y); 01088 if (Crosshair.shape == Dozen_Crosshair_Shape) 01089 draw_dozen_cross (xor_gc, x, y); 01090 } 01091 01092 void 01093 ghid_init_renderer (int *argc, char ***argv, GHidPort *port) 01094 { 01095 /* Init any GC's required */ 01096 port->render_priv = g_new0 (render_priv, 1); 01097 port->render_priv->crosshair_gc = gui->graphics->make_gc (); 01098 } 01099 01100 void 01101 ghid_shutdown_renderer (GHidPort *port) 01102 { 01103 render_priv *priv = port->render_priv; 01104 01105 gui->graphics->destroy_gc (priv->crosshair_gc); 01106 ghid_cancel_lead_user (); 01107 g_free (port->render_priv); 01108 port->render_priv = NULL; 01109 } 01110 01111 void 01112 ghid_init_drawing_widget (GtkWidget *widget, GHidPort *port) 01113 { 01114 } 01115 01116 void 01117 ghid_drawing_area_configure_hook (GHidPort *port) 01118 { 01119 static int done_once = 0; 01120 render_priv *priv = port->render_priv; 01121 01122 if (!done_once) 01123 { 01124 priv->bg_gc = gdk_gc_new (port->drawable); 01125 gdk_gc_set_foreground (priv->bg_gc, &port->bg_color); 01126 gdk_gc_set_clip_origin (priv->bg_gc, 0, 0); 01127 01128 priv->offlimits_gc = gdk_gc_new (port->drawable); 01129 gdk_gc_set_foreground (priv->offlimits_gc, &port->offlimits_color); 01130 gdk_gc_set_clip_origin (priv->offlimits_gc, 0, 0); 01131 done_once = 1; 01132 } 01133 01134 if (port->mask) 01135 { 01136 g_object_unref (port->mask); 01137 port->mask = gdk_pixmap_new (0, port->width, port->height, 1); 01138 } 01139 } 01140 01141 void 01142 ghid_screen_update (void) 01143 { 01144 render_priv *priv = gport->render_priv; 01145 GdkWindow *window = gtk_widget_get_window (gport->drawing_area); 01146 01147 if (gport->pixmap == NULL) 01148 return; 01149 01150 gdk_draw_drawable (window, priv->bg_gc, gport->pixmap, 01151 0, 0, 0, 0, gport->width, gport->height); 01152 draw_crosshair (priv); 01153 } 01154 01155 gboolean 01156 ghid_drawing_area_expose_cb (GtkWidget *widget, 01157 GdkEventExpose *ev, 01158 GHidPort *port) 01159 { 01160 render_priv *priv = port->render_priv; 01161 GdkWindow *window = gtk_widget_get_window (gport->drawing_area); 01162 01163 gdk_draw_drawable (window, priv->bg_gc, port->pixmap, 01164 ev->area.x, ev->area.y, ev->area.x, ev->area.y, 01165 ev->area.width, ev->area.height); 01166 draw_crosshair (priv); 01167 return FALSE; 01168 } 01169 01170 void 01171 ghid_port_drawing_realize_cb (GtkWidget *widget, gpointer data) 01172 { 01173 } 01174 01175 gboolean 01176 ghid_pinout_preview_expose (GtkWidget *widget, 01177 GdkEventExpose *ev) 01178 { 01179 GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW (widget); 01180 GdkWindow *window = gtk_widget_get_window (widget); 01181 GdkDrawable *save_drawable; 01182 GtkAllocation allocation; 01183 view_data save_view; 01184 int save_width, save_height; 01185 Coord save_max_width; 01186 Coord save_max_height; 01187 double xz, yz; 01188 render_priv *priv = gport->render_priv; 01189 01190 /* Setup drawable and zoom factor for drawing routines 01191 */ 01192 save_drawable = gport->drawable; 01193 save_view = gport->view; 01194 save_width = gport->width; 01195 save_height = gport->height; 01196 save_max_width = PCB->MaxWidth; 01197 save_max_height = PCB->MaxHeight; 01198 01199 gtk_widget_get_allocation (widget, &allocation); 01200 xz = (double) pinout->x_max / allocation.width; 01201 yz = (double) pinout->y_max / allocation.height; 01202 if (xz > yz) 01203 gport->view.coord_per_px = xz; 01204 else 01205 gport->view.coord_per_px = yz; 01206 01207 gport->drawable = window; 01208 gport->width = allocation.width; 01209 gport->height = allocation.height; 01210 gport->view.width = allocation.width * gport->view.coord_per_px; 01211 gport->view.height = allocation.height * gport->view.coord_per_px; 01212 gport->view.x0 = (pinout->x_max - gport->view.width) / 2; 01213 gport->view.y0 = (pinout->y_max - gport->view.height) / 2; 01214 PCB->MaxWidth = pinout->x_max; 01215 PCB->MaxHeight = pinout->y_max; 01216 01217 /* clear background */ 01218 gdk_draw_rectangle (window, priv->bg_gc, TRUE, 01219 0, 0, allocation.width, allocation.height); 01220 01221 /* call the drawing routine */ 01222 hid_expose_callback (&ghid_hid, NULL, pinout->element); 01223 01224 gport->drawable = save_drawable; 01225 gport->view = save_view; 01226 gport->width = save_width; 01227 gport->height = save_height; 01228 PCB->MaxWidth = save_max_width; 01229 PCB->MaxHeight = save_max_height; 01230 01231 return FALSE; 01232 } 01233 01234 GdkPixmap * 01235 ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int depth) 01236 { 01237 GdkPixmap *pixmap; 01238 GdkDrawable *save_drawable; 01239 view_data save_view; 01240 int save_width, save_height; 01241 BoxType region; 01242 render_priv *priv = gport->render_priv; 01243 01244 save_drawable = gport->drawable; 01245 save_view = gport->view; 01246 save_width = gport->width; 01247 save_height = gport->height; 01248 01249 pixmap = gdk_pixmap_new (NULL, width, height, depth); 01250 01251 /* Setup drawable and zoom factor for drawing routines 01252 */ 01253 01254 gport->drawable = pixmap; 01255 gport->view.coord_per_px = zoom; 01256 gport->width = width; 01257 gport->height = height; 01258 gport->view.width = width * gport->view.coord_per_px; 01259 gport->view.height = height * gport->view.coord_per_px; 01260 gport->view.x0 = gport->view.flip_x ? PCB->MaxWidth - cx : cx; 01261 gport->view.x0 -= gport->view.height / 2; 01262 gport->view.y0 = gport->view.flip_y ? PCB->MaxHeight - cy : cy; 01263 gport->view.y0 -= gport->view.width / 2; 01264 01265 /* clear background */ 01266 gdk_draw_rectangle (pixmap, priv->bg_gc, TRUE, 0, 0, width, height); 01267 01268 /* call the drawing routine */ 01269 region.X1 = MIN(Px(0), Px(gport->width + 1)); 01270 region.Y1 = MIN(Py(0), Py(gport->height + 1)); 01271 region.X2 = MAX(Px(0), Px(gport->width + 1)); 01272 region.Y2 = MAX(Py(0), Py(gport->height + 1)); 01273 01274 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1)); 01275 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2)); 01276 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1)); 01277 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2)); 01278 01279 hid_expose_callback (&ghid_hid, ®ion, NULL); 01280 01281 gport->drawable = save_drawable; 01282 gport->view = save_view; 01283 gport->width = save_width; 01284 gport->height = save_height; 01285 01286 return pixmap; 01287 } 01288 01289 HID_DRAW * 01290 ghid_request_debug_draw (void) 01291 { 01292 /* No special setup requirements, drawing goes into 01293 * the backing pixmap. */ 01294 return ghid_hid.graphics; 01295 } 01296 01297 void 01298 ghid_flush_debug_draw (void) 01299 { 01300 ghid_screen_update (); 01301 gdk_flush (); 01302 } 01303 01304 void 01305 ghid_finish_debug_draw (void) 01306 { 01307 ghid_flush_debug_draw (); 01308 /* No special tear down requirements 01309 */ 01310 } 01311 01312 bool 01313 ghid_event_to_pcb_coords (int event_x, int event_y, Coord *pcb_x, Coord *pcb_y) 01314 { 01315 *pcb_x = EVENT_TO_PCB_X (event_x); 01316 *pcb_y = EVENT_TO_PCB_Y (event_y); 01317 01318 return true; 01319 } 01320 01321 bool 01322 ghid_pcb_to_event_coords (Coord pcb_x, Coord pcb_y, int *event_x, int *event_y) 01323 { 01324 *event_x = DRAW_X (pcb_x); 01325 *event_y = DRAW_Y (pcb_y); 01326 01327 return true; 01328 } 01329 01330 01331 #define LEAD_USER_WIDTH 0.2 /* millimeters */ 01332 #define LEAD_USER_PERIOD (1000 / 5) /* 5fps (in ms) */ 01333 #define LEAD_USER_VELOCITY 3. /* millimeters per second */ 01334 #define LEAD_USER_ARC_COUNT 3 01335 #define LEAD_USER_ARC_SEPARATION 3. /* millimeters */ 01336 #define LEAD_USER_INITIAL_RADIUS 10. /* millimetres */ 01337 #define LEAD_USER_COLOR_R 1. 01338 #define LEAD_USER_COLOR_G 1. 01339 #define LEAD_USER_COLOR_B 0. 01340 01341 static void 01342 draw_lead_user (render_priv *priv) 01343 { 01344 GdkWindow *window = gtk_widget_get_window (gport->drawing_area); 01345 GtkStyle *style = gtk_widget_get_style (gport->drawing_area); 01346 int i; 01347 Coord radius = priv->lead_user_radius; 01348 Coord width = MM_TO_COORD (LEAD_USER_WIDTH); 01349 Coord separation = MM_TO_COORD (LEAD_USER_ARC_SEPARATION); 01350 static GdkGC *lead_gc = NULL; 01351 GdkColor lead_color; 01352 01353 if (!priv->lead_user) 01354 return; 01355 01356 if (lead_gc == NULL) 01357 { 01358 lead_gc = gdk_gc_new (window); 01359 gdk_gc_copy (lead_gc, style->white_gc); 01360 gdk_gc_set_function (lead_gc, GDK_XOR); 01361 gdk_gc_set_clip_origin (lead_gc, 0, 0); 01362 lead_color.pixel = 0; 01363 lead_color.red = (int)(65535. * LEAD_USER_COLOR_R); 01364 lead_color.green = (int)(65535. * LEAD_USER_COLOR_G); 01365 lead_color.blue = (int)(65535. * LEAD_USER_COLOR_B); 01366 gdk_color_alloc (gport->colormap, &lead_color); 01367 gdk_gc_set_foreground (lead_gc, &lead_color); 01368 } 01369 01370 set_clip (priv, lead_gc); 01371 gdk_gc_set_line_attributes (lead_gc, Vz (width), 01372 GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER); 01373 01374 /* arcs at the approrpriate radii */ 01375 01376 for (i = 0; i < LEAD_USER_ARC_COUNT; i++, radius -= separation) 01377 { 01378 if (radius < width) 01379 radius += MM_TO_COORD (LEAD_USER_INITIAL_RADIUS); 01380 01381 /* Draw an arc at radius */ 01382 gdk_draw_arc (gport->drawable, lead_gc, FALSE, 01383 Vx (priv->lead_user_x - radius), 01384 Vy (priv->lead_user_y - radius), 01385 Vz (2. * radius), Vz (2. * radius), 01386 0, 360 * 64); 01387 } 01388 } 01389 01390 gboolean 01391 lead_user_cb (gpointer data) 01392 { 01393 render_priv *priv = data; 01394 Coord step; 01395 double elapsed_time; 01396 01397 /* Queue a redraw */ 01398 ghid_invalidate_all (); 01399 01400 /* Update radius */ 01401 elapsed_time = g_timer_elapsed (priv->lead_user_timer, NULL); 01402 g_timer_start (priv->lead_user_timer); 01403 01404 step = MM_TO_COORD (LEAD_USER_VELOCITY * elapsed_time); 01405 if (priv->lead_user_radius > step) 01406 priv->lead_user_radius -= step; 01407 else 01408 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS); 01409 01410 return TRUE; 01411 } 01412 01413 void 01414 ghid_lead_user_to_location (Coord x, Coord y) 01415 { 01416 render_priv *priv = gport->render_priv; 01417 01418 ghid_cancel_lead_user (); 01419 01420 priv->lead_user = true; 01421 priv->lead_user_x = x; 01422 priv->lead_user_y = y; 01423 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS); 01424 priv->lead_user_timeout = g_timeout_add (LEAD_USER_PERIOD, lead_user_cb, priv); 01425 priv->lead_user_timer = g_timer_new (); 01426 } 01427 01428 void 01429 ghid_cancel_lead_user (void) 01430 { 01431 render_priv *priv = gport->render_priv; 01432 01433 if (priv->lead_user_timeout) 01434 g_source_remove (priv->lead_user_timeout); 01435 01436 if (priv->lead_user_timer) 01437 g_timer_destroy (priv->lead_user_timer); 01438 01439 if (priv->lead_user) 01440 ghid_invalidate_all (); 01441 01442 priv->lead_user_timeout = 0; 01443 priv->lead_user_timer = NULL; 01444 priv->lead_user = false; 01445 }