Fix distribution of gnet-pcbfwd.scm in the dist tarball
[geda-pcb/gde.git] / src / crosshair.c
blob367922e0e705bd949651c2ff6811476671cabdc2
1 /* $Id$ */
2 /* 15 Oct 2008 Ineiev: add different crosshair shapes */
4 /*
5 * COPYRIGHT
7 * PCB, interactive printed circuit board design
8 * Copyright (C) 1994,1995,1996 Thomas Nau
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 * Contact addresses for paper mail and Email:
25 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
26 * Thomas.Nau@rz.uni-ulm.de
31 /* crosshair stuff
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
38 #include <memory.h>
39 #include <math.h>
41 #include "global.h"
43 #include "crosshair.h"
44 #include "data.h"
45 #include "draw.h"
46 #include "error.h"
47 #include "line.h"
48 #include "misc.h"
49 #include "mymem.h"
50 #include "search.h"
52 #ifdef HAVE_LIBDMALLOC
53 #include <dmalloc.h>
54 #endif
56 RCSID ("$Id$");
58 #if !defined(ABS)
59 #define ABS(x) (((x)<0)?-(x):(x))
60 #endif
62 typedef struct
64 int x, y;
65 } point;
67 /* ---------------------------------------------------------------------------
68 * some local identifiers
71 /* This is a stack for HideCrosshair() and RestoreCrosshair() calls. They
72 * must always be matched. */
73 static Boolean CrosshairStack[MAX_CROSSHAIRSTACK_DEPTH];
74 static int CrosshairStackLocation = 0;
76 /* ---------------------------------------------------------------------------
77 * some local prototypes
79 static void XORPolygon (PolygonTypePtr, LocationType, LocationType);
80 static void XORDrawElement (ElementTypePtr, LocationType, LocationType);
81 static void XORDrawBuffer (BufferTypePtr);
82 static void XORDrawInsertPointObject (void);
83 static void XORDrawMoveOrCopyObject (void);
84 static void XORDrawAttachedLine (LocationType, LocationType, LocationType,
85 LocationType, BDimension);
86 static void XORDrawAttachedArc (BDimension);
87 static void DrawAttached (Boolean);
89 /* ---------------------------------------------------------------------------
90 * creates a tmp polygon with coordinates converted to screen system
92 static void
93 XORPolygon (PolygonTypePtr polygon, LocationType dx, LocationType dy)
95 int i;
96 for (i = 0; i < polygon->PointN - 1; i++)
97 gui->draw_line (Crosshair.GC,
98 polygon->Points[i].X + dx, polygon->Points[i].Y + dy,
99 polygon->Points[i + 1].X + dx,
100 polygon->Points[i + 1].Y + dy);
101 if (i > 1)
102 gui->draw_line (Crosshair.GC,
103 polygon->Points[i].X + dx, polygon->Points[i].Y + dy,
104 polygon->Points[0].X + dx, polygon->Points[0].Y + dy);
107 /*-----------------------------------------------------------
108 * Draws the outline of an arc
110 static void
111 XORDrawAttachedArc (BDimension thick)
113 ArcType arc;
114 BoxTypePtr bx;
115 LocationType wx, wy;
116 int sa, dir;
117 BDimension wid = thick / 2;
119 wx = Crosshair.X - Crosshair.AttachedBox.Point1.X;
120 wy = Crosshair.Y - Crosshair.AttachedBox.Point1.Y;
121 if (wx == 0 && wy == 0)
122 return;
123 arc.X = Crosshair.AttachedBox.Point1.X;
124 arc.Y = Crosshair.AttachedBox.Point1.Y;
125 if (XOR (Crosshair.AttachedBox.otherway, abs (wy) > abs (wx)))
127 arc.X = Crosshair.AttachedBox.Point1.X + abs (wy) * SGNZ (wx);
128 sa = (wx >= 0) ? 0 : 180;
129 #ifdef ARC45
130 if (abs (wy) >= 2 * abs (wx))
131 dir = (SGNZ (wx) == SGNZ (wy)) ? 45 : -45;
132 else
133 #endif
134 dir = (SGNZ (wx) == SGNZ (wy)) ? 90 : -90;
136 else
138 arc.Y = Crosshair.AttachedBox.Point1.Y + abs (wx) * SGNZ (wy);
139 sa = (wy >= 0) ? -90 : 90;
140 #ifdef ARC45
141 if (abs (wx) >= 2 * abs (wy))
142 dir = (SGNZ (wx) == SGNZ (wy)) ? -45 : 45;
143 else
144 #endif
145 dir = (SGNZ (wx) == SGNZ (wy)) ? -90 : 90;
146 wy = wx;
148 wy = abs (wy);
149 arc.StartAngle = sa;
150 arc.Delta = dir;
151 arc.Width = arc.Height = wy;
152 bx = GetArcEnds (&arc);
153 /* sa = sa - 180; */
154 gui->draw_arc (Crosshair.GC, arc.X, arc.Y, wy + wid, wy + wid, sa, dir);
155 if (wid > pixel_slop)
157 gui->draw_arc (Crosshair.GC, arc.X, arc.Y, wy - wid, wy - wid, sa, dir);
158 gui->draw_arc (Crosshair.GC, bx->X1, bx->Y1,
159 wid, wid, sa, -180 * SGN (dir));
160 gui->draw_arc (Crosshair.GC, bx->X2, bx->Y2,
161 wid, wid, sa + dir, 180 * SGN (dir));
165 /*-----------------------------------------------------------
166 * Draws the outline of a line
168 static void
169 XORDrawAttachedLine (LocationType x1, LocationType y1, LocationType x2,
170 LocationType y2, BDimension thick)
172 LocationType dx, dy, ox, oy;
173 float h;
175 dx = x2 - x1;
176 dy = y2 - y1;
177 if (dx != 0 || dy != 0)
178 h = 0.5 * thick / sqrt (SQUARE (dx) + SQUARE (dy));
179 else
180 h = 0.0;
181 ox = dy * h + 0.5 * SGN (dy);
182 oy = -(dx * h + 0.5 * SGN (dx));
183 gui->draw_line (Crosshair.GC, x1 + ox, y1 + oy, x2 + ox, y2 + oy);
184 if (abs (ox) >= pixel_slop || abs (oy) >= pixel_slop)
186 LocationType angle = atan2 ((float) dx, (float) dy) * 57.295779;
187 gui->draw_line (Crosshair.GC, x1 - ox, y1 - oy, x2 - ox, y2 - oy);
188 gui->draw_arc (Crosshair.GC,
189 x1, y1, thick / 2, thick / 2, angle - 180, 180);
190 gui->draw_arc (Crosshair.GC, x2, y2, thick / 2, thick / 2, angle, 180);
194 /* ---------------------------------------------------------------------------
195 * draws the elements of a loaded circuit which is to be merged in
197 static void
198 XORDrawElement (ElementTypePtr Element, LocationType DX, LocationType DY)
200 /* if no silkscreen, draw the bounding box */
201 if (Element->ArcN == 0 && Element->LineN == 0)
203 gui->draw_line (Crosshair.GC,
204 DX + Element->BoundingBox.X1,
205 DY + Element->BoundingBox.Y1,
206 DX + Element->BoundingBox.X1,
207 DY + Element->BoundingBox.Y2);
208 gui->draw_line (Crosshair.GC,
209 DX + Element->BoundingBox.X1,
210 DY + Element->BoundingBox.Y2,
211 DX + Element->BoundingBox.X2,
212 DY + Element->BoundingBox.Y2);
213 gui->draw_line (Crosshair.GC,
214 DX + Element->BoundingBox.X2,
215 DY + Element->BoundingBox.Y2,
216 DX + Element->BoundingBox.X2,
217 DY + Element->BoundingBox.Y1);
218 gui->draw_line (Crosshair.GC,
219 DX + Element->BoundingBox.X2,
220 DY + Element->BoundingBox.Y1,
221 DX + Element->BoundingBox.X1,
222 DY + Element->BoundingBox.Y1);
224 else
226 ELEMENTLINE_LOOP (Element);
228 gui->draw_line (Crosshair.GC,
229 DX + line->Point1.X,
230 DY + line->Point1.Y,
231 DX + line->Point2.X, DY + line->Point2.Y);
233 END_LOOP;
235 /* arc coordinates and angles have to be converted to X11 notation */
236 ARC_LOOP (Element);
238 gui->draw_arc (Crosshair.GC,
239 DX + arc->X,
240 DY + arc->Y,
241 arc->Width, arc->Height, arc->StartAngle, arc->Delta);
243 END_LOOP;
245 /* pin coordinates and angles have to be converted to X11 notation */
246 PIN_LOOP (Element);
248 gui->draw_arc (Crosshair.GC,
249 DX + pin->X,
250 DY + pin->Y,
251 pin->Thickness / 2, pin->Thickness / 2, 0, 360);
253 END_LOOP;
255 /* pads */
256 PAD_LOOP (Element);
258 if ((TEST_FLAG (ONSOLDERFLAG, pad) != 0) ==
259 Settings.ShowSolderSide || PCB->InvisibleObjectsOn)
261 if (pad->Point1.X == pad->Point2.X
262 || pad->Point1.Y == pad->Point2.Y)
264 int minx, miny, maxx, maxy;
265 minx = DX + MIN (pad->Point1.X, pad->Point2.X) - pad->Thickness/2;
266 maxx = DX + MAX (pad->Point1.X, pad->Point2.X) + pad->Thickness/2;
267 miny = DY + MIN (pad->Point1.Y, pad->Point2.Y) - pad->Thickness/2;
268 maxy = DY + MAX (pad->Point1.Y, pad->Point2.Y) + pad->Thickness/2;
269 gui->draw_line (Crosshair.GC, minx, miny, maxx, miny);
270 gui->draw_line (Crosshair.GC, minx, miny, minx, maxy);
271 gui->draw_line (Crosshair.GC, maxx, miny, maxx, maxy);
272 gui->draw_line (Crosshair.GC, minx, maxy, maxx, maxy);
274 else
276 /* FIXME: draw outlines, not centerlines. */
277 gui->draw_line (Crosshair.GC,
278 DX + pad->Point1.X, DY + pad->Point1.Y,
279 DX + pad->Point2.X, DY + pad->Point2.Y);
283 END_LOOP;
284 /* mark */
285 gui->draw_line (Crosshair.GC,
286 Element->MarkX + DX - EMARK_SIZE,
287 Element->MarkY + DY,
288 Element->MarkX + DX, Element->MarkY + DY - EMARK_SIZE);
289 gui->draw_line (Crosshair.GC,
290 Element->MarkX + DX + EMARK_SIZE,
291 Element->MarkY + DY,
292 Element->MarkX + DX, Element->MarkY + DY - EMARK_SIZE);
293 gui->draw_line (Crosshair.GC,
294 Element->MarkX + DX - EMARK_SIZE,
295 Element->MarkY + DY,
296 Element->MarkX + DX, Element->MarkY + DY + EMARK_SIZE);
297 gui->draw_line (Crosshair.GC,
298 Element->MarkX + DX + EMARK_SIZE,
299 Element->MarkY + DY,
300 Element->MarkX + DX, Element->MarkY + DY + EMARK_SIZE);
303 /* ---------------------------------------------------------------------------
304 * draws all visible and attached objects of the pastebuffer
306 static void
307 XORDrawBuffer (BufferTypePtr Buffer)
309 Cardinal i;
310 LocationType x, y;
312 /* set offset */
313 x = Crosshair.X - Buffer->X;
314 y = Crosshair.Y - Buffer->Y;
316 /* draw all visible layers */
317 for (i = 0; i < max_layer + 2; i++)
318 if (PCB->Data->Layer[i].On)
320 LayerTypePtr layer = &Buffer->Data->Layer[i];
322 LINE_LOOP (layer);
325 XORDrawAttachedLine(x +line->Point1.X,
326 y +line->Point1.Y, x +line->Point2.X,
327 y +line->Point2.Y, line->Thickness);
329 gui->draw_line (Crosshair.GC,
330 x + line->Point1.X, y + line->Point1.Y,
331 x + line->Point2.X, y + line->Point2.Y);
333 END_LOOP;
334 ARC_LOOP (layer);
336 gui->draw_arc (Crosshair.GC,
337 x + arc->X,
338 y + arc->Y,
339 arc->Width,
340 arc->Height, arc->StartAngle, arc->Delta);
342 END_LOOP;
343 TEXT_LOOP (layer);
345 BoxTypePtr box = &text->BoundingBox;
346 gui->draw_rect (Crosshair.GC,
347 x + box->X1, y + box->Y1, x + box->X2, y + box->Y2);
349 END_LOOP;
350 /* the tmp polygon has n+1 points because the first
351 * and the last one are set to the same coordinates
353 POLYGON_LOOP (layer);
355 XORPolygon (polygon, x, y);
357 END_LOOP;
360 /* draw elements if visible */
361 if (PCB->PinOn && PCB->ElementOn)
362 ELEMENT_LOOP (Buffer->Data);
364 if (FRONT (element) || PCB->InvisibleObjectsOn)
365 XORDrawElement (element, x, y);
367 END_LOOP;
369 /* and the vias, move offset by thickness/2 */
370 if (PCB->ViaOn)
371 VIA_LOOP (Buffer->Data);
373 gui->draw_arc (Crosshair.GC,
374 x + via->X, y + via->Y,
375 via->Thickness / 2, via->Thickness / 2, 0, 360);
377 END_LOOP;
380 /* ---------------------------------------------------------------------------
381 * draws the rubberband to insert points into polygons/lines/...
383 static void
384 XORDrawInsertPointObject (void)
386 LineTypePtr line = (LineTypePtr) Crosshair.AttachedObject.Ptr2;
387 PointTypePtr point = (PointTypePtr) Crosshair.AttachedObject.Ptr3;
389 if (Crosshair.AttachedObject.Type != NO_TYPE)
391 gui->draw_line (Crosshair.GC,
392 point->X, point->Y, line->Point1.X, line->Point1.Y);
393 gui->draw_line (Crosshair.GC,
394 point->X, point->Y, line->Point2.X, line->Point2.Y);
398 /* ---------------------------------------------------------------------------
399 * draws the attached object while in MOVE_MODE or COPY_MODE
401 static void
402 XORDrawMoveOrCopyObject (void)
404 RubberbandTypePtr ptr;
405 Cardinal i;
406 LocationType dx = Crosshair.X - Crosshair.AttachedObject.X,
407 dy = Crosshair.Y - Crosshair.AttachedObject.Y;
409 switch (Crosshair.AttachedObject.Type)
411 case VIA_TYPE:
413 PinTypePtr via = (PinTypePtr) Crosshair.AttachedObject.Ptr1;
415 gui->draw_arc (Crosshair.GC,
416 via->X + dx,
417 via->Y + dy,
418 via->Thickness / 2, via->Thickness / 2, 0, 360);
419 break;
422 case LINE_TYPE:
424 LineTypePtr line = (LineTypePtr) Crosshair.AttachedObject.Ptr2;
426 XORDrawAttachedLine (line->Point1.X + dx, line->Point1.Y + dy,
427 line->Point2.X + dx, line->Point2.Y + dy,
428 line->Thickness);
429 break;
432 case ARC_TYPE:
434 ArcTypePtr Arc = (ArcTypePtr) Crosshair.AttachedObject.Ptr2;
436 gui->draw_arc (Crosshair.GC,
437 Arc->X + dx,
438 Arc->Y + dy,
439 Arc->Width, Arc->Height, Arc->StartAngle, Arc->Delta);
440 break;
443 case POLYGON_TYPE:
445 PolygonTypePtr polygon =
446 (PolygonTypePtr) Crosshair.AttachedObject.Ptr2;
448 /* the tmp polygon has n+1 points because the first
449 * and the last one are set to the same coordinates
451 XORPolygon (polygon, dx, dy);
452 break;
455 case LINEPOINT_TYPE:
457 LineTypePtr line;
458 PointTypePtr point;
460 line = (LineTypePtr) Crosshair.AttachedObject.Ptr2;
461 point = (PointTypePtr) Crosshair.AttachedObject.Ptr3;
462 if (point == &line->Point1)
463 XORDrawAttachedLine (point->X + dx,
464 point->Y + dy, line->Point2.X,
465 line->Point2.Y, line->Thickness);
466 else
467 XORDrawAttachedLine (point->X + dx,
468 point->Y + dy, line->Point1.X,
469 line->Point1.Y, line->Thickness);
470 break;
473 case POLYGONPOINT_TYPE:
475 PolygonTypePtr polygon;
476 PointTypePtr point, previous, following;
478 polygon = (PolygonTypePtr) Crosshair.AttachedObject.Ptr2;
479 point = (PointTypePtr) Crosshair.AttachedObject.Ptr3;
481 /* get previous and following point */
482 if (point == polygon->Points)
484 previous = &polygon->Points[polygon->PointN - 1];
485 following = point + 1;
487 else if (point == &polygon->Points[polygon->PointN - 1])
489 previous = point - 1;
490 following = &polygon->Points[0];
492 else
494 previous = point - 1;
495 following = point + 1;
498 /* draw the two segments */
499 gui->draw_line (Crosshair.GC,
500 previous->X,
501 previous->Y, point->X + dx, point->Y + dy);
502 gui->draw_line (Crosshair.GC,
503 point->X + dx,
504 point->Y + dy, following->X, following->Y);
505 break;
508 case ELEMENTNAME_TYPE:
510 /* locate the element "mark" and draw an association line from crosshair to it */
511 ElementTypePtr element =
512 (ElementTypePtr) Crosshair.AttachedObject.Ptr1;
514 gui->draw_line (Crosshair.GC,
515 element->MarkX,
516 element->MarkY, Crosshair.X, Crosshair.Y);
517 /* fall through to move the text as a box outline */
519 case TEXT_TYPE:
521 TextTypePtr text = (TextTypePtr) Crosshair.AttachedObject.Ptr2;
522 BoxTypePtr box = &text->BoundingBox;
523 gui->draw_rect (Crosshair.GC,
524 box->X1 + dx,
525 box->Y1 + dy, box->X2 + dx, box->Y2 + dy);
526 break;
529 /* pin/pad movements result in moving an element */
530 case PAD_TYPE:
531 case PIN_TYPE:
532 case ELEMENT_TYPE:
533 XORDrawElement ((ElementTypePtr) Crosshair.AttachedObject.Ptr2, dx, dy);
534 break;
537 /* draw the attached rubberband lines too */
538 i = Crosshair.AttachedObject.RubberbandN;
539 ptr = Crosshair.AttachedObject.Rubberband;
540 while (i)
542 PointTypePtr point1, point2;
544 if (TEST_FLAG (VIAFLAG, ptr->Line))
546 /* this is a rat going to a polygon. do not draw for rubberband */;
548 else if (TEST_FLAG (RUBBERENDFLAG, ptr->Line))
550 /* 'point1' is always the fix-point */
551 if (ptr->MovedPoint == &ptr->Line->Point1)
553 point1 = &ptr->Line->Point2;
554 point2 = &ptr->Line->Point1;
556 else
558 point1 = &ptr->Line->Point1;
559 point2 = &ptr->Line->Point2;
561 XORDrawAttachedLine (point1->X,
562 point1->Y, point2->X + dx,
563 point2->Y + dy, ptr->Line->Thickness);
565 else if (ptr->MovedPoint == &ptr->Line->Point1)
566 XORDrawAttachedLine (ptr->Line->Point1.X + dx,
567 ptr->Line->Point1.Y + dy,
568 ptr->Line->Point2.X + dx,
569 ptr->Line->Point2.Y + dy, ptr->Line->Thickness);
571 ptr++;
572 i--;
576 /* ---------------------------------------------------------------------------
577 * draws additional stuff that follows the crosshair
579 static void
580 DrawAttached (Boolean BlockToo)
582 BDimension s;
583 switch (Settings.Mode)
585 case VIA_MODE:
586 gui->draw_arc (Crosshair.GC,
587 Crosshair.X,
588 Crosshair.Y,
589 Settings.ViaThickness / 2,
590 Settings.ViaThickness / 2, 0, 360);
591 if (TEST_FLAG (SHOWDRCFLAG, PCB))
593 s = Settings.ViaThickness / 2 + PCB->Bloat + 1;
594 gui->set_color (Crosshair.GC, Settings.CrossColor);
595 gui->draw_arc (Crosshair.GC,
596 Crosshair.X, Crosshair.Y, s, s, 0, 360);
597 gui->set_color (Crosshair.GC, Settings.CrosshairColor);
599 break;
601 /* the attached line is used by both LINEMODE and POLYGON_MODE */
602 case POLYGON_MODE:
603 /* draw only if starting point is set */
604 if (Crosshair.AttachedLine.State != STATE_FIRST)
605 gui->draw_line (Crosshair.GC,
606 Crosshair.AttachedLine.Point1.X,
607 Crosshair.AttachedLine.Point1.Y,
608 Crosshair.AttachedLine.Point2.X,
609 Crosshair.AttachedLine.Point2.Y);
611 /* draw attached polygon only if in POLYGON_MODE */
612 if (Crosshair.AttachedPolygon.PointN > 1)
614 XORPolygon (&Crosshair.AttachedPolygon, 0, 0);
616 break;
618 case ARC_MODE:
619 if (Crosshair.AttachedBox.State != STATE_FIRST)
621 XORDrawAttachedArc (Settings.LineThickness);
622 if (TEST_FLAG (SHOWDRCFLAG, PCB))
624 gui->set_color (Crosshair.GC, Settings.CrossColor);
625 XORDrawAttachedArc (Settings.LineThickness +
626 2 * (PCB->Bloat + 1));
627 gui->set_color (Crosshair.GC, Settings.CrosshairColor);
631 break;
633 case LINE_MODE:
634 /* draw only if starting point exists and the line has length */
635 if (Crosshair.AttachedLine.State != STATE_FIRST &&
636 Crosshair.AttachedLine.draw)
638 XORDrawAttachedLine (Crosshair.AttachedLine.Point1.X,
639 Crosshair.AttachedLine.Point1.Y,
640 Crosshair.AttachedLine.Point2.X,
641 Crosshair.AttachedLine.Point2.Y,
642 PCB->RatDraw ? 10 : Settings.LineThickness);
643 /* draw two lines ? */
644 if (PCB->Clipping)
645 XORDrawAttachedLine (Crosshair.AttachedLine.Point2.X,
646 Crosshair.AttachedLine.Point2.Y,
647 Crosshair.X, Crosshair.Y,
648 PCB->RatDraw ? 10 : Settings.LineThickness);
649 if (TEST_FLAG (SHOWDRCFLAG, PCB))
651 gui->set_color (Crosshair.GC, Settings.CrossColor);
652 XORDrawAttachedLine (Crosshair.AttachedLine.Point1.X,
653 Crosshair.AttachedLine.Point1.Y,
654 Crosshair.AttachedLine.Point2.X,
655 Crosshair.AttachedLine.Point2.Y,
656 PCB->RatDraw ? 10 : Settings.LineThickness
657 + 2 * (PCB->Bloat + 1));
658 if (PCB->Clipping)
659 XORDrawAttachedLine (Crosshair.AttachedLine.Point2.X,
660 Crosshair.AttachedLine.Point2.Y,
661 Crosshair.X, Crosshair.Y,
662 PCB->RatDraw ? 10 : Settings.
663 LineThickness + 2 * (PCB->Bloat + 1));
664 gui->set_color (Crosshair.GC, Settings.CrosshairColor);
667 break;
669 case PASTEBUFFER_MODE:
670 XORDrawBuffer (PASTEBUFFER);
671 break;
673 case COPY_MODE:
674 case MOVE_MODE:
675 XORDrawMoveOrCopyObject ();
676 break;
678 case INSERTPOINT_MODE:
679 XORDrawInsertPointObject ();
680 break;
683 /* an attached box does not depend on a special mode */
684 if (Crosshair.AttachedBox.State == STATE_SECOND ||
685 (BlockToo && Crosshair.AttachedBox.State == STATE_THIRD))
687 LocationType x1, y1, x2, y2;
689 x1 = Crosshair.AttachedBox.Point1.X;
690 y1 = Crosshair.AttachedBox.Point1.Y;
691 x2 = Crosshair.AttachedBox.Point2.X;
692 y2 = Crosshair.AttachedBox.Point2.Y;
693 gui->draw_rect (Crosshair.GC, x1, y1, x2, y2);
697 /* ---------------------------------------------------------------------------
698 * switches crosshair on
700 void
701 CrosshairOn (Boolean BlockToo)
703 if (!Crosshair.On)
705 Crosshair.On = True;
706 DrawAttached (BlockToo);
707 DrawMark (True);
711 /* ---------------------------------------------------------------------------
712 * switches crosshair off
714 void
715 CrosshairOff (Boolean BlockToo)
717 if (Crosshair.On)
719 Crosshair.On = False;
720 DrawAttached (BlockToo);
721 DrawMark (True);
726 * The parameter to HideCrosshair() and RestoreCrosshair() dictates whether
727 * the object you're dragging should be drawn or not.
729 * This argument is _not_ saved in the stack, so whether you have drawings
730 * following the cursor around or not is dependant on the parameter passed
731 * LAST to either of these two functions.
734 /* ---------------------------------------------------------------------------
735 * saves crosshair state (on/off) and hides him
737 void
738 HideCrosshair (Boolean BlockToo)
740 /* fprintf(stderr, "HideCrosshair %d stack %d\n", BlockToo ? 1 : 0, CrosshairStackLocation); */
741 if (CrosshairStackLocation >= MAX_CROSSHAIRSTACK_DEPTH)
743 fprintf(stderr, "Error: CrosshairStackLocation overflow\n");
744 return;
747 CrosshairStack[CrosshairStackLocation] = Crosshair.On;
748 CrosshairStackLocation++;
750 CrosshairOff (BlockToo);
753 /* ---------------------------------------------------------------------------
754 * restores last crosshair state
756 void
757 RestoreCrosshair (Boolean BlockToo)
759 /* fprintf(stderr, "RestoreCrosshair %d stack %d\n", BlockToo ? 1 : 0, CrosshairStackLocation); */
760 if (CrosshairStackLocation <= 0)
762 fprintf(stderr, "Error: CrosshairStackLocation underflow\n");
763 return;
766 CrosshairStackLocation--;
768 if (CrosshairStack[CrosshairStackLocation])
770 CrosshairOn (BlockToo);
772 else
774 CrosshairOff (BlockToo);
778 /* ---------------------------------------------------------------------------
779 * recalculates the passed coordinates to fit the current grid setting
781 void
782 FitCrosshairIntoGrid (LocationType X, LocationType Y)
784 LocationType x2, y2, x0, y0;
785 void *ptr1, *ptr2, *ptr3;
786 int ans;
788 x0 = 0;
789 y0 = 0;
790 x2 = PCB->MaxWidth;
791 y2 = PCB->MaxHeight;
792 Crosshair.X = MIN (Crosshair.MaxX, MAX (Crosshair.MinX, X));
793 Crosshair.Y = MIN (Crosshair.MaxY, MAX (Crosshair.MinY, Y));
795 if (PCB->RatDraw || TEST_FLAG (SNAPPINFLAG, PCB))
797 ans =
798 SearchScreen (Crosshair.X, Crosshair.Y,
799 PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3);
800 if (ans == NO_TYPE && !PCB->RatDraw)
801 ans =
802 SearchScreen (Crosshair.X, Crosshair.Y, VIA_TYPE | LINEPOINT_TYPE,
803 &ptr1, &ptr2, &ptr3);
804 if (ans == NO_TYPE && !PCB->RatDraw)
805 ans =
806 SearchScreen (Crosshair.X, Crosshair.Y, ELEMENT_TYPE, &ptr1, &ptr2,
807 &ptr3);
809 else
810 ans = NO_TYPE;
812 /* avoid self-snapping */
813 if (Settings.Mode == MOVE_MODE)
815 switch (Crosshair.AttachedObject.Type)
817 case ELEMENT_TYPE:
818 if ((ans & (PAD_TYPE | PIN_TYPE)) &&
819 ptr1 == Crosshair.AttachedObject.Ptr1)
820 ans = NO_TYPE;
821 break;
822 case VIA_TYPE:
823 /* just avoid snapping to any other vias */
824 if (ans & PIN_TYPES)
825 ans = NO_TYPE;
826 break;
830 if (PCB->RatDraw)
832 x0 = -600;
833 y0 = -600;
835 else
837 /* check if new position is inside the output window
838 * This might not be true after the window has been resized.
839 * In this case we just set it to the center of the window or
840 * with respect to the grid (if possible)
842 if (Crosshair.X < x0 || Crosshair.X > x2)
844 if (x2 + 1 >= PCB->Grid)
845 /* there must be a point that matches the grid
846 * so we just have to look for it with some integer
847 * calculations
849 x0 = GRIDFIT_X (PCB->Grid, PCB->Grid);
850 else
851 x0 = (x2) / 2;
853 else
854 /* check if the new position matches the grid */
855 x0 = GRIDFIT_X (Crosshair.X, PCB->Grid);
857 /* do the same for the second coordinate */
858 if (Crosshair.Y < y0 || Crosshair.Y > y2)
860 if (y2 + 1 >= PCB->Grid)
861 y0 = GRIDFIT_Y (PCB->Grid, PCB->Grid);
862 else
863 y0 = (y2) / 2;
865 else
866 y0 = GRIDFIT_Y (Crosshair.Y, PCB->Grid);
868 if (Marked.status && TEST_FLAG (ORTHOMOVEFLAG, PCB))
870 int dx = Crosshair.X - Marked.X;
871 int dy = Crosshair.Y - Marked.Y;
872 if (ABS (dx) > ABS (dy))
873 y0 = Marked.Y;
874 else
875 x0 = Marked.X;
879 if (ans & PAD_TYPE)
881 PadTypePtr pad = (PadTypePtr) ptr2;
882 LocationType px, py;
884 px = (pad->Point1.X + pad->Point2.X) / 2;
885 py = (pad->Point1.Y + pad->Point2.Y) / 2;
887 if (!gui->shift_is_pressed()
888 || (SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) >
889 SQUARE (px - Crosshair.X) + SQUARE (py - Crosshair.Y)))
891 x0 = px;
892 y0 = py;
896 else if (ans & (PIN_TYPE | VIA_TYPE))
898 PinTypePtr pin = (PinTypePtr) ptr2;
899 if (!gui->shift_is_pressed()
900 || (SQUARE (x0 - Crosshair.X) +
901 SQUARE (y0 - Crosshair.Y) >
902 SQUARE (pin->X - Crosshair.X) + SQUARE (pin->Y - Crosshair.Y)))
904 x0 = pin->X;
905 y0 = pin->Y;
908 else if (ans & LINEPOINT_TYPE)
910 PointTypePtr pnt = (PointTypePtr) ptr3;
911 if (((x0 - Crosshair.X) * (x0 - Crosshair.X) +
912 (y0 - Crosshair.Y) * (y0 - Crosshair.Y)) >
913 ((pnt->X - Crosshair.X) * (pnt->X - Crosshair.X) +
914 (pnt->Y - Crosshair.Y) * (pnt->Y - Crosshair.Y)))
916 x0 = pnt->X;
917 y0 = pnt->Y;
920 else if (ans & ELEMENT_TYPE)
922 ElementTypePtr el = (ElementTypePtr) ptr1;
923 if (SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) >
924 SQUARE (el->MarkX - Crosshair.X) + SQUARE (el->MarkY - Crosshair.Y))
926 x0 = el->MarkX;
927 y0 = el->MarkY;
930 if (x0 >= 0 && y0 >= 0)
932 Crosshair.X = x0;
933 Crosshair.Y = y0;
935 if (Settings.Mode == ARROW_MODE)
937 ans =
938 SearchScreen (Crosshair.X, Crosshair.Y, LINEPOINT_TYPE,
939 &ptr1, &ptr2, &ptr3);
940 if (ans == NO_TYPE)
941 hid_action("PointCursor");
942 else if (!TEST_FLAG(SELECTEDFLAG, (LineType *)ptr2))
943 hid_actionl("PointCursor","True", NULL);
945 if (Settings.Mode == LINE_MODE
946 && Crosshair.AttachedLine.State != STATE_FIRST
947 && TEST_FLAG (AUTODRCFLAG, PCB))
948 EnforceLineDRC ();
950 gui->set_crosshair (Crosshair.X, Crosshair.Y, HID_SC_DO_NOTHING);
953 /* ---------------------------------------------------------------------------
954 * move crosshair relative (has to be switched off)
956 void
957 MoveCrosshairRelative (LocationType DeltaX, LocationType DeltaY)
959 FitCrosshairIntoGrid (Crosshair.X + DeltaX, Crosshair.Y + DeltaY);
962 /* ---------------------------------------------------------------------------
963 * move crosshair absolute switched off if it moved
964 * return True if it switched off
966 Boolean
967 MoveCrosshairAbsolute (LocationType X, LocationType Y)
969 LocationType x, y, z;
970 x = Crosshair.X;
971 y = Crosshair.Y;
972 FitCrosshairIntoGrid (X, Y);
973 if (Crosshair.X != x || Crosshair.Y != y)
975 /* back up to old position and erase crosshair */
976 z = Crosshair.X;
977 Crosshair.X = x;
978 x = z;
979 z = Crosshair.Y;
980 Crosshair.Y = y;
981 HideCrosshair (False);
982 /* now move forward again */
983 Crosshair.X = x;
984 Crosshair.Y = z;
985 return (True);
987 return (False);
990 /* ---------------------------------------------------------------------------
991 * sets the valid range for the crosshair cursor
993 void
994 SetCrosshairRange (LocationType MinX, LocationType MinY, LocationType MaxX,
995 LocationType MaxY)
997 Crosshair.MinX = MAX (0, MinX);
998 Crosshair.MinY = MAX (0, MinY);
999 Crosshair.MaxX = MIN ((LocationType) PCB->MaxWidth, MaxX);
1000 Crosshair.MaxY = MIN ((LocationType) PCB->MaxHeight, MaxY);
1002 /* force update of position */
1003 MoveCrosshairRelative (0, 0);
1006 /* --------------------------------------------------------------------------
1007 * draw the marker position
1008 * if argument is True, draw only if it is visible, otherwise draw it regardless
1010 void
1011 DrawMark (Boolean ifvis)
1013 if (Marked.status || !ifvis)
1015 gui->draw_line (Crosshair.GC,
1016 Marked.X - MARK_SIZE,
1017 Marked.Y - MARK_SIZE,
1018 Marked.X + MARK_SIZE, Marked.Y + MARK_SIZE);
1019 gui->draw_line (Crosshair.GC,
1020 Marked.X + MARK_SIZE,
1021 Marked.Y - MARK_SIZE,
1022 Marked.X - MARK_SIZE, Marked.Y + MARK_SIZE);
1026 /* ---------------------------------------------------------------------------
1027 * initializes crosshair stuff
1028 * clears the struct, allocates to graphical contexts and
1029 * initializes the stack
1031 void
1032 InitCrosshair (void)
1034 Crosshair.GC = gui->make_gc ();
1036 gui->set_color (Crosshair.GC, Settings.CrosshairColor);
1037 gui->set_draw_xor (Crosshair.GC, 1);
1038 gui->set_line_cap (Crosshair.GC, Trace_Cap);
1039 gui->set_line_width (Crosshair.GC, 1);
1041 /* fake a crosshair off entry on stack */
1042 CrosshairStackLocation = 0;
1043 CrosshairStack[CrosshairStackLocation++] = True;
1044 Crosshair.On = False;
1046 /* set initial shape */
1047 Crosshair.shape = Basic_Crosshair_Shape;
1049 /* set default limits */
1050 Crosshair.MinX = Crosshair.MinY = 0;
1051 Crosshair.MaxX = PCB->MaxWidth;
1052 Crosshair.MaxY = PCB->MaxHeight;
1054 /* clear the mark */
1055 Marked.status = False;
1058 /* ---------------------------------------------------------------------------
1059 * exits crosshair routines, release GCs
1061 void
1062 DestroyCrosshair (void)
1064 CrosshairOff (True);
1065 FreePolygonMemory (&Crosshair.AttachedPolygon);
1066 gui->destroy_gc (Crosshair.GC);