Introduce POLYGONHOLE_MODE for creating holes in polygons
[geda-pcb/gde.git] / src / crosshair.c
blobb9a3dd2b3d7147745b4ea79f46a6b69eb0c90fbe
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"
51 #include "polygon.h"
53 #ifdef HAVE_LIBDMALLOC
54 #include <dmalloc.h>
55 #endif
57 RCSID ("$Id$");
59 #if !defined(ABS)
60 #define ABS(x) (((x)<0)?-(x):(x))
61 #endif
63 typedef struct
65 int x, y;
66 } point;
68 /* ---------------------------------------------------------------------------
69 * some local identifiers
72 /* This is a stack for HideCrosshair() and RestoreCrosshair() calls. They
73 * must always be matched. */
74 static bool CrosshairStack[MAX_CROSSHAIRSTACK_DEPTH];
75 static int CrosshairStackLocation = 0;
77 /* ---------------------------------------------------------------------------
78 * some local prototypes
80 static void XORPolygon (PolygonTypePtr, LocationType, LocationType);
81 static void XORDrawElement (ElementTypePtr, LocationType, LocationType);
82 static void XORDrawBuffer (BufferTypePtr);
83 static void XORDrawInsertPointObject (void);
84 static void XORDrawMoveOrCopyObject (void);
85 static void XORDrawAttachedLine (LocationType, LocationType, LocationType,
86 LocationType, BDimension);
87 static void XORDrawAttachedArc (BDimension);
88 static void DrawAttached (bool);
90 /* ---------------------------------------------------------------------------
91 * creates a tmp polygon with coordinates converted to screen system
93 static void
94 XORPolygon (PolygonTypePtr polygon, LocationType dx, LocationType dy)
96 Cardinal i;
97 for (i = 0; i < polygon->PointN; i++)
99 Cardinal next = next_contour_point (polygon, i);
100 gui->draw_line (Crosshair.GC,
101 polygon->Points[i].X + dx,
102 polygon->Points[i].Y + dy,
103 polygon->Points[next].X + dx,
104 polygon->Points[next].Y + dy);
108 /*-----------------------------------------------------------
109 * Draws the outline of an arc
111 static void
112 XORDrawAttachedArc (BDimension thick)
114 ArcType arc;
115 BoxTypePtr bx;
116 LocationType wx, wy;
117 int sa, dir;
118 BDimension wid = thick / 2;
120 wx = Crosshair.X - Crosshair.AttachedBox.Point1.X;
121 wy = Crosshair.Y - Crosshair.AttachedBox.Point1.Y;
122 if (wx == 0 && wy == 0)
123 return;
124 arc.X = Crosshair.AttachedBox.Point1.X;
125 arc.Y = Crosshair.AttachedBox.Point1.Y;
126 if (XOR (Crosshair.AttachedBox.otherway, abs (wy) > abs (wx)))
128 arc.X = Crosshair.AttachedBox.Point1.X + abs (wy) * SGNZ (wx);
129 sa = (wx >= 0) ? 0 : 180;
130 #ifdef ARC45
131 if (abs (wy) >= 2 * abs (wx))
132 dir = (SGNZ (wx) == SGNZ (wy)) ? 45 : -45;
133 else
134 #endif
135 dir = (SGNZ (wx) == SGNZ (wy)) ? 90 : -90;
137 else
139 arc.Y = Crosshair.AttachedBox.Point1.Y + abs (wx) * SGNZ (wy);
140 sa = (wy >= 0) ? -90 : 90;
141 #ifdef ARC45
142 if (abs (wx) >= 2 * abs (wy))
143 dir = (SGNZ (wx) == SGNZ (wy)) ? -45 : 45;
144 else
145 #endif
146 dir = (SGNZ (wx) == SGNZ (wy)) ? -90 : 90;
147 wy = wx;
149 wy = abs (wy);
150 arc.StartAngle = sa;
151 arc.Delta = dir;
152 arc.Width = arc.Height = wy;
153 bx = GetArcEnds (&arc);
154 /* sa = sa - 180; */
155 gui->draw_arc (Crosshair.GC, arc.X, arc.Y, wy + wid, wy + wid, sa, dir);
156 if (wid > pixel_slop)
158 gui->draw_arc (Crosshair.GC, arc.X, arc.Y, wy - wid, wy - wid, sa, dir);
159 gui->draw_arc (Crosshair.GC, bx->X1, bx->Y1,
160 wid, wid, sa, -180 * SGN (dir));
161 gui->draw_arc (Crosshair.GC, bx->X2, bx->Y2,
162 wid, wid, sa + dir, 180 * SGN (dir));
166 /*-----------------------------------------------------------
167 * Draws the outline of a line
169 static void
170 XORDrawAttachedLine (LocationType x1, LocationType y1, LocationType x2,
171 LocationType y2, BDimension thick)
173 LocationType dx, dy, ox, oy;
174 float h;
176 dx = x2 - x1;
177 dy = y2 - y1;
178 if (dx != 0 || dy != 0)
179 h = 0.5 * thick / sqrt (SQUARE (dx) + SQUARE (dy));
180 else
181 h = 0.0;
182 ox = dy * h + 0.5 * SGN (dy);
183 oy = -(dx * h + 0.5 * SGN (dx));
184 gui->draw_line (Crosshair.GC, x1 + ox, y1 + oy, x2 + ox, y2 + oy);
185 if (abs (ox) >= pixel_slop || abs (oy) >= pixel_slop)
187 LocationType angle = atan2 ((float) dx, (float) dy) * 57.295779;
188 gui->draw_line (Crosshair.GC, x1 - ox, y1 - oy, x2 - ox, y2 - oy);
189 gui->draw_arc (Crosshair.GC,
190 x1, y1, thick / 2, thick / 2, angle - 180, 180);
191 gui->draw_arc (Crosshair.GC, x2, y2, thick / 2, thick / 2, angle, 180);
195 /* ---------------------------------------------------------------------------
196 * draws the elements of a loaded circuit which is to be merged in
198 static void
199 XORDrawElement (ElementTypePtr Element, LocationType DX, LocationType DY)
201 /* if no silkscreen, draw the bounding box */
202 if (Element->ArcN == 0 && Element->LineN == 0)
204 gui->draw_line (Crosshair.GC,
205 DX + Element->BoundingBox.X1,
206 DY + Element->BoundingBox.Y1,
207 DX + Element->BoundingBox.X1,
208 DY + Element->BoundingBox.Y2);
209 gui->draw_line (Crosshair.GC,
210 DX + Element->BoundingBox.X1,
211 DY + Element->BoundingBox.Y2,
212 DX + Element->BoundingBox.X2,
213 DY + Element->BoundingBox.Y2);
214 gui->draw_line (Crosshair.GC,
215 DX + Element->BoundingBox.X2,
216 DY + Element->BoundingBox.Y2,
217 DX + Element->BoundingBox.X2,
218 DY + Element->BoundingBox.Y1);
219 gui->draw_line (Crosshair.GC,
220 DX + Element->BoundingBox.X2,
221 DY + Element->BoundingBox.Y1,
222 DX + Element->BoundingBox.X1,
223 DY + Element->BoundingBox.Y1);
225 else
227 ELEMENTLINE_LOOP (Element);
229 gui->draw_line (Crosshair.GC,
230 DX + line->Point1.X,
231 DY + line->Point1.Y,
232 DX + line->Point2.X, DY + line->Point2.Y);
234 END_LOOP;
236 /* arc coordinates and angles have to be converted to X11 notation */
237 ARC_LOOP (Element);
239 gui->draw_arc (Crosshair.GC,
240 DX + arc->X,
241 DY + arc->Y,
242 arc->Width, arc->Height, arc->StartAngle, arc->Delta);
244 END_LOOP;
246 /* pin coordinates and angles have to be converted to X11 notation */
247 PIN_LOOP (Element);
249 gui->draw_arc (Crosshair.GC,
250 DX + pin->X,
251 DY + pin->Y,
252 pin->Thickness / 2, pin->Thickness / 2, 0, 360);
254 END_LOOP;
256 /* pads */
257 PAD_LOOP (Element);
259 if ((TEST_FLAG (ONSOLDERFLAG, pad) != 0) ==
260 Settings.ShowSolderSide || PCB->InvisibleObjectsOn)
262 if (pad->Point1.X == pad->Point2.X
263 || pad->Point1.Y == pad->Point2.Y)
265 int minx, miny, maxx, maxy;
266 minx = DX + MIN (pad->Point1.X, pad->Point2.X) - pad->Thickness/2;
267 maxx = DX + MAX (pad->Point1.X, pad->Point2.X) + pad->Thickness/2;
268 miny = DY + MIN (pad->Point1.Y, pad->Point2.Y) - pad->Thickness/2;
269 maxy = DY + MAX (pad->Point1.Y, pad->Point2.Y) + pad->Thickness/2;
270 gui->draw_line (Crosshair.GC, minx, miny, maxx, miny);
271 gui->draw_line (Crosshair.GC, minx, miny, minx, maxy);
272 gui->draw_line (Crosshair.GC, maxx, miny, maxx, maxy);
273 gui->draw_line (Crosshair.GC, minx, maxy, maxx, maxy);
275 else
277 /* FIXME: draw outlines, not centerlines. */
278 gui->draw_line (Crosshair.GC,
279 DX + pad->Point1.X, DY + pad->Point1.Y,
280 DX + pad->Point2.X, DY + pad->Point2.Y);
284 END_LOOP;
285 /* mark */
286 gui->draw_line (Crosshair.GC,
287 Element->MarkX + DX - EMARK_SIZE,
288 Element->MarkY + DY,
289 Element->MarkX + DX, Element->MarkY + DY - EMARK_SIZE);
290 gui->draw_line (Crosshair.GC,
291 Element->MarkX + DX + EMARK_SIZE,
292 Element->MarkY + DY,
293 Element->MarkX + DX, Element->MarkY + DY - EMARK_SIZE);
294 gui->draw_line (Crosshair.GC,
295 Element->MarkX + DX - EMARK_SIZE,
296 Element->MarkY + DY,
297 Element->MarkX + DX, Element->MarkY + DY + EMARK_SIZE);
298 gui->draw_line (Crosshair.GC,
299 Element->MarkX + DX + EMARK_SIZE,
300 Element->MarkY + DY,
301 Element->MarkX + DX, Element->MarkY + DY + EMARK_SIZE);
304 /* ---------------------------------------------------------------------------
305 * draws all visible and attached objects of the pastebuffer
307 static void
308 XORDrawBuffer (BufferTypePtr Buffer)
310 Cardinal i;
311 LocationType x, y;
313 /* set offset */
314 x = Crosshair.X - Buffer->X;
315 y = Crosshair.Y - Buffer->Y;
317 /* draw all visible layers */
318 for (i = 0; i < max_layer + 2; i++)
319 if (PCB->Data->Layer[i].On)
321 LayerTypePtr layer = &Buffer->Data->Layer[i];
323 LINE_LOOP (layer);
326 XORDrawAttachedLine(x +line->Point1.X,
327 y +line->Point1.Y, x +line->Point2.X,
328 y +line->Point2.Y, line->Thickness);
330 gui->draw_line (Crosshair.GC,
331 x + line->Point1.X, y + line->Point1.Y,
332 x + line->Point2.X, y + line->Point2.Y);
334 END_LOOP;
335 ARC_LOOP (layer);
337 gui->draw_arc (Crosshair.GC,
338 x + arc->X,
339 y + arc->Y,
340 arc->Width,
341 arc->Height, arc->StartAngle, arc->Delta);
343 END_LOOP;
344 TEXT_LOOP (layer);
346 BoxTypePtr box = &text->BoundingBox;
347 gui->draw_rect (Crosshair.GC,
348 x + box->X1, y + box->Y1, x + box->X2, y + box->Y2);
350 END_LOOP;
351 /* the tmp polygon has n+1 points because the first
352 * and the last one are set to the same coordinates
354 POLYGON_LOOP (layer);
356 XORPolygon (polygon, x, y);
358 END_LOOP;
361 /* draw elements if visible */
362 if (PCB->PinOn && PCB->ElementOn)
363 ELEMENT_LOOP (Buffer->Data);
365 if (FRONT (element) || PCB->InvisibleObjectsOn)
366 XORDrawElement (element, x, y);
368 END_LOOP;
370 /* and the vias, move offset by thickness/2 */
371 if (PCB->ViaOn)
372 VIA_LOOP (Buffer->Data);
374 gui->draw_arc (Crosshair.GC,
375 x + via->X, y + via->Y,
376 via->Thickness / 2, via->Thickness / 2, 0, 360);
378 END_LOOP;
381 /* ---------------------------------------------------------------------------
382 * draws the rubberband to insert points into polygons/lines/...
384 static void
385 XORDrawInsertPointObject (void)
387 LineTypePtr line = (LineTypePtr) Crosshair.AttachedObject.Ptr2;
388 PointTypePtr point = (PointTypePtr) Crosshair.AttachedObject.Ptr3;
390 if (Crosshair.AttachedObject.Type != NO_TYPE)
392 gui->draw_line (Crosshair.GC,
393 point->X, point->Y, line->Point1.X, line->Point1.Y);
394 gui->draw_line (Crosshair.GC,
395 point->X, point->Y, line->Point2.X, line->Point2.Y);
399 /* ---------------------------------------------------------------------------
400 * draws the attached object while in MOVE_MODE or COPY_MODE
402 static void
403 XORDrawMoveOrCopyObject (void)
405 RubberbandTypePtr ptr;
406 Cardinal i;
407 LocationType dx = Crosshair.X - Crosshair.AttachedObject.X,
408 dy = Crosshair.Y - Crosshair.AttachedObject.Y;
410 switch (Crosshair.AttachedObject.Type)
412 case VIA_TYPE:
414 PinTypePtr via = (PinTypePtr) Crosshair.AttachedObject.Ptr1;
416 gui->draw_arc (Crosshair.GC,
417 via->X + dx,
418 via->Y + dy,
419 via->Thickness / 2, via->Thickness / 2, 0, 360);
420 break;
423 case LINE_TYPE:
425 LineTypePtr line = (LineTypePtr) Crosshair.AttachedObject.Ptr2;
427 XORDrawAttachedLine (line->Point1.X + dx, line->Point1.Y + dy,
428 line->Point2.X + dx, line->Point2.Y + dy,
429 line->Thickness);
430 break;
433 case ARC_TYPE:
435 ArcTypePtr Arc = (ArcTypePtr) Crosshair.AttachedObject.Ptr2;
437 gui->draw_arc (Crosshair.GC,
438 Arc->X + dx,
439 Arc->Y + dy,
440 Arc->Width, Arc->Height, Arc->StartAngle, Arc->Delta);
441 break;
444 case POLYGON_TYPE:
446 PolygonTypePtr polygon =
447 (PolygonTypePtr) Crosshair.AttachedObject.Ptr2;
449 /* the tmp polygon has n+1 points because the first
450 * and the last one are set to the same coordinates
452 XORPolygon (polygon, dx, dy);
453 break;
456 case LINEPOINT_TYPE:
458 LineTypePtr line;
459 PointTypePtr point;
461 line = (LineTypePtr) Crosshair.AttachedObject.Ptr2;
462 point = (PointTypePtr) Crosshair.AttachedObject.Ptr3;
463 if (point == &line->Point1)
464 XORDrawAttachedLine (point->X + dx,
465 point->Y + dy, line->Point2.X,
466 line->Point2.Y, line->Thickness);
467 else
468 XORDrawAttachedLine (point->X + dx,
469 point->Y + dy, line->Point1.X,
470 line->Point1.Y, line->Thickness);
471 break;
474 case POLYGONPOINT_TYPE:
476 PolygonTypePtr polygon;
477 PointTypePtr point;
478 Cardinal point_idx, prev, next;
480 polygon = (PolygonTypePtr) Crosshair.AttachedObject.Ptr2;
481 point = (PointTypePtr) Crosshair.AttachedObject.Ptr3;
482 point_idx = polygon_point_idx (polygon, point);
484 /* get previous and following point */
485 prev = prev_contour_point (polygon, point_idx);
486 next = next_contour_point (polygon, point_idx);
488 /* draw the two segments */
489 gui->draw_line (Crosshair.GC,
490 polygon->Points[prev].X, polygon->Points[prev].Y,
491 point->X + dx, point->Y + dy);
492 gui->draw_line (Crosshair.GC,
493 point->X + dx, point->Y + dy,
494 polygon->Points[next].X, polygon->Points[next].Y);
495 break;
498 case ELEMENTNAME_TYPE:
500 /* locate the element "mark" and draw an association line from crosshair to it */
501 ElementTypePtr element =
502 (ElementTypePtr) Crosshair.AttachedObject.Ptr1;
504 gui->draw_line (Crosshair.GC,
505 element->MarkX,
506 element->MarkY, Crosshair.X, Crosshair.Y);
507 /* fall through to move the text as a box outline */
509 case TEXT_TYPE:
511 TextTypePtr text = (TextTypePtr) Crosshair.AttachedObject.Ptr2;
512 BoxTypePtr box = &text->BoundingBox;
513 gui->draw_rect (Crosshair.GC,
514 box->X1 + dx,
515 box->Y1 + dy, box->X2 + dx, box->Y2 + dy);
516 break;
519 /* pin/pad movements result in moving an element */
520 case PAD_TYPE:
521 case PIN_TYPE:
522 case ELEMENT_TYPE:
523 XORDrawElement ((ElementTypePtr) Crosshair.AttachedObject.Ptr2, dx, dy);
524 break;
527 /* draw the attached rubberband lines too */
528 i = Crosshair.AttachedObject.RubberbandN;
529 ptr = Crosshair.AttachedObject.Rubberband;
530 while (i)
532 PointTypePtr point1, point2;
534 if (TEST_FLAG (VIAFLAG, ptr->Line))
536 /* this is a rat going to a polygon. do not draw for rubberband */;
538 else if (TEST_FLAG (RUBBERENDFLAG, ptr->Line))
540 /* 'point1' is always the fix-point */
541 if (ptr->MovedPoint == &ptr->Line->Point1)
543 point1 = &ptr->Line->Point2;
544 point2 = &ptr->Line->Point1;
546 else
548 point1 = &ptr->Line->Point1;
549 point2 = &ptr->Line->Point2;
551 XORDrawAttachedLine (point1->X,
552 point1->Y, point2->X + dx,
553 point2->Y + dy, ptr->Line->Thickness);
555 else if (ptr->MovedPoint == &ptr->Line->Point1)
556 XORDrawAttachedLine (ptr->Line->Point1.X + dx,
557 ptr->Line->Point1.Y + dy,
558 ptr->Line->Point2.X + dx,
559 ptr->Line->Point2.Y + dy, ptr->Line->Thickness);
561 ptr++;
562 i--;
566 /* ---------------------------------------------------------------------------
567 * draws additional stuff that follows the crosshair
569 static void
570 DrawAttached (bool BlockToo)
572 BDimension s;
573 switch (Settings.Mode)
575 case VIA_MODE:
576 gui->draw_arc (Crosshair.GC,
577 Crosshair.X,
578 Crosshair.Y,
579 Settings.ViaThickness / 2,
580 Settings.ViaThickness / 2, 0, 360);
581 if (TEST_FLAG (SHOWDRCFLAG, PCB))
583 s = Settings.ViaThickness / 2 + PCB->Bloat + 1;
584 gui->set_color (Crosshair.GC, Settings.CrossColor);
585 gui->draw_arc (Crosshair.GC,
586 Crosshair.X, Crosshair.Y, s, s, 0, 360);
587 gui->set_color (Crosshair.GC, Settings.CrosshairColor);
589 break;
591 /* the attached line is used by both LINEMODE, POLYGON_MODE and POLYGONHOLE_MODE*/
592 case POLYGON_MODE:
593 case POLYGONHOLE_MODE:
594 /* draw only if starting point is set */
595 if (Crosshair.AttachedLine.State != STATE_FIRST)
596 gui->draw_line (Crosshair.GC,
597 Crosshair.AttachedLine.Point1.X,
598 Crosshair.AttachedLine.Point1.Y,
599 Crosshair.AttachedLine.Point2.X,
600 Crosshair.AttachedLine.Point2.Y);
602 /* draw attached polygon only if in POLYGON_MODE or POLYGONHOLE_MODE */
603 if (Crosshair.AttachedPolygon.PointN > 1)
605 XORPolygon (&Crosshair.AttachedPolygon, 0, 0);
607 break;
609 case ARC_MODE:
610 if (Crosshair.AttachedBox.State != STATE_FIRST)
612 XORDrawAttachedArc (Settings.LineThickness);
613 if (TEST_FLAG (SHOWDRCFLAG, PCB))
615 gui->set_color (Crosshair.GC, Settings.CrossColor);
616 XORDrawAttachedArc (Settings.LineThickness +
617 2 * (PCB->Bloat + 1));
618 gui->set_color (Crosshair.GC, Settings.CrosshairColor);
622 break;
624 case LINE_MODE:
625 /* draw only if starting point exists and the line has length */
626 if (Crosshair.AttachedLine.State != STATE_FIRST &&
627 Crosshair.AttachedLine.draw)
629 XORDrawAttachedLine (Crosshair.AttachedLine.Point1.X,
630 Crosshair.AttachedLine.Point1.Y,
631 Crosshair.AttachedLine.Point2.X,
632 Crosshair.AttachedLine.Point2.Y,
633 PCB->RatDraw ? 10 : Settings.LineThickness);
634 /* draw two lines ? */
635 if (PCB->Clipping)
636 XORDrawAttachedLine (Crosshair.AttachedLine.Point2.X,
637 Crosshair.AttachedLine.Point2.Y,
638 Crosshair.X, Crosshair.Y,
639 PCB->RatDraw ? 10 : Settings.LineThickness);
640 if (TEST_FLAG (SHOWDRCFLAG, PCB))
642 gui->set_color (Crosshair.GC, Settings.CrossColor);
643 XORDrawAttachedLine (Crosshair.AttachedLine.Point1.X,
644 Crosshair.AttachedLine.Point1.Y,
645 Crosshair.AttachedLine.Point2.X,
646 Crosshair.AttachedLine.Point2.Y,
647 PCB->RatDraw ? 10 : Settings.LineThickness
648 + 2 * (PCB->Bloat + 1));
649 if (PCB->Clipping)
650 XORDrawAttachedLine (Crosshair.AttachedLine.Point2.X,
651 Crosshair.AttachedLine.Point2.Y,
652 Crosshair.X, Crosshair.Y,
653 PCB->RatDraw ? 10 : Settings.
654 LineThickness + 2 * (PCB->Bloat + 1));
655 gui->set_color (Crosshair.GC, Settings.CrosshairColor);
658 break;
660 case PASTEBUFFER_MODE:
661 XORDrawBuffer (PASTEBUFFER);
662 break;
664 case COPY_MODE:
665 case MOVE_MODE:
666 XORDrawMoveOrCopyObject ();
667 break;
669 case INSERTPOINT_MODE:
670 XORDrawInsertPointObject ();
671 break;
674 /* an attached box does not depend on a special mode */
675 if (Crosshair.AttachedBox.State == STATE_SECOND ||
676 (BlockToo && Crosshair.AttachedBox.State == STATE_THIRD))
678 LocationType x1, y1, x2, y2;
680 x1 = Crosshair.AttachedBox.Point1.X;
681 y1 = Crosshair.AttachedBox.Point1.Y;
682 x2 = Crosshair.AttachedBox.Point2.X;
683 y2 = Crosshair.AttachedBox.Point2.Y;
684 gui->draw_rect (Crosshair.GC, x1, y1, x2, y2);
688 /* ---------------------------------------------------------------------------
689 * switches crosshair on
691 void
692 CrosshairOn (bool BlockToo)
694 if (!Crosshair.On)
696 Crosshair.On = true;
697 DrawAttached (BlockToo);
698 DrawMark (true);
702 /* ---------------------------------------------------------------------------
703 * switches crosshair off
705 void
706 CrosshairOff (bool BlockToo)
708 if (Crosshair.On)
710 Crosshair.On = false;
711 DrawAttached (BlockToo);
712 DrawMark (true);
717 * The parameter to HideCrosshair() and RestoreCrosshair() dictates whether
718 * the object you're dragging should be drawn or not.
720 * This argument is _not_ saved in the stack, so whether you have drawings
721 * following the cursor around or not is dependant on the parameter passed
722 * LAST to either of these two functions.
725 /* ---------------------------------------------------------------------------
726 * saves crosshair state (on/off) and hides him
728 void
729 HideCrosshair (bool BlockToo)
731 /* fprintf(stderr, "HideCrosshair %d stack %d\n", BlockToo ? 1 : 0, CrosshairStackLocation); */
732 if (CrosshairStackLocation >= MAX_CROSSHAIRSTACK_DEPTH)
734 fprintf(stderr, "Error: CrosshairStackLocation overflow\n");
735 return;
738 CrosshairStack[CrosshairStackLocation] = Crosshair.On;
739 CrosshairStackLocation++;
741 CrosshairOff (BlockToo);
744 /* ---------------------------------------------------------------------------
745 * restores last crosshair state
747 void
748 RestoreCrosshair (bool BlockToo)
750 /* fprintf(stderr, "RestoreCrosshair %d stack %d\n", BlockToo ? 1 : 0, CrosshairStackLocation); */
751 if (CrosshairStackLocation <= 0)
753 fprintf(stderr, "Error: CrosshairStackLocation underflow\n");
754 return;
757 CrosshairStackLocation--;
759 if (CrosshairStack[CrosshairStackLocation])
761 CrosshairOn (BlockToo);
763 else
765 CrosshairOff (BlockToo);
769 /* ---------------------------------------------------------------------------
770 * recalculates the passed coordinates to fit the current grid setting
772 void
773 FitCrosshairIntoGrid (LocationType X, LocationType Y)
775 LocationType x2, y2, x0, y0;
776 void *ptr1, *ptr2, *ptr3;
777 int ans;
779 x0 = 0;
780 y0 = 0;
781 x2 = PCB->MaxWidth;
782 y2 = PCB->MaxHeight;
783 Crosshair.X = MIN (Crosshair.MaxX, MAX (Crosshair.MinX, X));
784 Crosshair.Y = MIN (Crosshair.MaxY, MAX (Crosshair.MinY, Y));
786 if (PCB->RatDraw || TEST_FLAG (SNAPPINFLAG, PCB))
788 ans =
789 SearchScreen (Crosshair.X, Crosshair.Y,
790 PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3);
791 if (ans == NO_TYPE && !PCB->RatDraw)
792 ans =
793 SearchScreen (Crosshair.X, Crosshair.Y, VIA_TYPE | LINEPOINT_TYPE,
794 &ptr1, &ptr2, &ptr3);
795 if (ans == NO_TYPE && !PCB->RatDraw)
796 ans =
797 SearchScreen (Crosshair.X, Crosshair.Y, ELEMENT_TYPE, &ptr1, &ptr2,
798 &ptr3);
800 else
801 ans = NO_TYPE;
803 /* avoid self-snapping */
804 if (Settings.Mode == MOVE_MODE)
806 switch (Crosshair.AttachedObject.Type)
808 case ELEMENT_TYPE:
809 if ((ans & (PAD_TYPE | PIN_TYPE)) &&
810 ptr1 == Crosshair.AttachedObject.Ptr1)
811 ans = NO_TYPE;
812 break;
813 case VIA_TYPE:
814 /* just avoid snapping to any other vias */
815 if (ans & PIN_TYPES)
816 ans = NO_TYPE;
817 break;
821 if (PCB->RatDraw)
823 x0 = -600;
824 y0 = -600;
826 else
828 /* check if new position is inside the output window
829 * This might not be true after the window has been resized.
830 * In this case we just set it to the center of the window or
831 * with respect to the grid (if possible)
833 if (Crosshair.X < x0 || Crosshair.X > x2)
835 if (x2 + 1 >= PCB->Grid)
836 /* there must be a point that matches the grid
837 * so we just have to look for it with some integer
838 * calculations
840 x0 = GRIDFIT_X (PCB->Grid, PCB->Grid);
841 else
842 x0 = (x2) / 2;
844 else
845 /* check if the new position matches the grid */
846 x0 = GRIDFIT_X (Crosshair.X, PCB->Grid);
848 /* do the same for the second coordinate */
849 if (Crosshair.Y < y0 || Crosshair.Y > y2)
851 if (y2 + 1 >= PCB->Grid)
852 y0 = GRIDFIT_Y (PCB->Grid, PCB->Grid);
853 else
854 y0 = (y2) / 2;
856 else
857 y0 = GRIDFIT_Y (Crosshair.Y, PCB->Grid);
859 if (Marked.status && TEST_FLAG (ORTHOMOVEFLAG, PCB))
861 int dx = Crosshair.X - Marked.X;
862 int dy = Crosshair.Y - Marked.Y;
863 if (ABS (dx) > ABS (dy))
864 y0 = Marked.Y;
865 else
866 x0 = Marked.X;
870 if (ans & PAD_TYPE)
872 PadTypePtr pad = (PadTypePtr) ptr2;
873 LocationType px, py;
875 px = (pad->Point1.X + pad->Point2.X) / 2;
876 py = (pad->Point1.Y + pad->Point2.Y) / 2;
878 if (!gui->shift_is_pressed()
879 || (SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) >
880 SQUARE (px - Crosshair.X) + SQUARE (py - Crosshair.Y)))
882 x0 = px;
883 y0 = py;
887 else if (ans & (PIN_TYPE | VIA_TYPE))
889 PinTypePtr pin = (PinTypePtr) ptr2;
890 if (!gui->shift_is_pressed()
891 || (SQUARE (x0 - Crosshair.X) +
892 SQUARE (y0 - Crosshair.Y) >
893 SQUARE (pin->X - Crosshair.X) + SQUARE (pin->Y - Crosshair.Y)))
895 x0 = pin->X;
896 y0 = pin->Y;
899 else if (ans & LINEPOINT_TYPE)
901 PointTypePtr pnt = (PointTypePtr) ptr3;
902 if (((x0 - Crosshair.X) * (x0 - Crosshair.X) +
903 (y0 - Crosshair.Y) * (y0 - Crosshair.Y)) >
904 ((pnt->X - Crosshair.X) * (pnt->X - Crosshair.X) +
905 (pnt->Y - Crosshair.Y) * (pnt->Y - Crosshair.Y)))
907 x0 = pnt->X;
908 y0 = pnt->Y;
911 else if (ans & ELEMENT_TYPE)
913 ElementTypePtr el = (ElementTypePtr) ptr1;
914 if (SQUARE (x0 - Crosshair.X) + SQUARE (y0 - Crosshair.Y) >
915 SQUARE (el->MarkX - Crosshair.X) + SQUARE (el->MarkY - Crosshair.Y))
917 x0 = el->MarkX;
918 y0 = el->MarkY;
921 if (x0 >= 0 && y0 >= 0)
923 Crosshair.X = x0;
924 Crosshair.Y = y0;
926 if (Settings.Mode == ARROW_MODE)
928 ans =
929 SearchScreen (Crosshair.X, Crosshair.Y, LINEPOINT_TYPE,
930 &ptr1, &ptr2, &ptr3);
931 if (ans == NO_TYPE)
932 hid_action("PointCursor");
933 else if (!TEST_FLAG(SELECTEDFLAG, (LineType *)ptr2))
934 hid_actionl("PointCursor","True", NULL);
936 if (Settings.Mode == LINE_MODE
937 && Crosshair.AttachedLine.State != STATE_FIRST
938 && TEST_FLAG (AUTODRCFLAG, PCB))
939 EnforceLineDRC ();
941 gui->set_crosshair (Crosshair.X, Crosshair.Y, HID_SC_DO_NOTHING);
944 /* ---------------------------------------------------------------------------
945 * move crosshair relative (has to be switched off)
947 void
948 MoveCrosshairRelative (LocationType DeltaX, LocationType DeltaY)
950 FitCrosshairIntoGrid (Crosshair.X + DeltaX, Crosshair.Y + DeltaY);
953 /* ---------------------------------------------------------------------------
954 * move crosshair absolute switched off if it moved
955 * return true if it switched off
957 bool
958 MoveCrosshairAbsolute (LocationType X, LocationType Y)
960 LocationType x, y, z;
961 x = Crosshair.X;
962 y = Crosshair.Y;
963 FitCrosshairIntoGrid (X, Y);
964 if (Crosshair.X != x || Crosshair.Y != y)
966 /* back up to old position and erase crosshair */
967 z = Crosshair.X;
968 Crosshair.X = x;
969 x = z;
970 z = Crosshair.Y;
971 Crosshair.Y = y;
972 HideCrosshair (false);
973 /* now move forward again */
974 Crosshair.X = x;
975 Crosshair.Y = z;
976 return (true);
978 return (false);
981 /* ---------------------------------------------------------------------------
982 * sets the valid range for the crosshair cursor
984 void
985 SetCrosshairRange (LocationType MinX, LocationType MinY, LocationType MaxX,
986 LocationType MaxY)
988 Crosshair.MinX = MAX (0, MinX);
989 Crosshair.MinY = MAX (0, MinY);
990 Crosshair.MaxX = MIN ((LocationType) PCB->MaxWidth, MaxX);
991 Crosshair.MaxY = MIN ((LocationType) PCB->MaxHeight, MaxY);
993 /* force update of position */
994 MoveCrosshairRelative (0, 0);
997 /* --------------------------------------------------------------------------
998 * draw the marker position
999 * if argument is true, draw only if it is visible, otherwise draw it regardless
1001 void
1002 DrawMark (bool ifvis)
1004 if (Marked.status || !ifvis)
1006 gui->draw_line (Crosshair.GC,
1007 Marked.X - MARK_SIZE,
1008 Marked.Y - MARK_SIZE,
1009 Marked.X + MARK_SIZE, Marked.Y + MARK_SIZE);
1010 gui->draw_line (Crosshair.GC,
1011 Marked.X + MARK_SIZE,
1012 Marked.Y - MARK_SIZE,
1013 Marked.X - MARK_SIZE, Marked.Y + MARK_SIZE);
1017 /* ---------------------------------------------------------------------------
1018 * initializes crosshair stuff
1019 * clears the struct, allocates to graphical contexts and
1020 * initializes the stack
1022 void
1023 InitCrosshair (void)
1025 Crosshair.GC = gui->make_gc ();
1027 gui->set_color (Crosshair.GC, Settings.CrosshairColor);
1028 gui->set_draw_xor (Crosshair.GC, 1);
1029 gui->set_line_cap (Crosshair.GC, Trace_Cap);
1030 gui->set_line_width (Crosshair.GC, 1);
1032 /* fake a crosshair off entry on stack */
1033 CrosshairStackLocation = 0;
1034 CrosshairStack[CrosshairStackLocation++] = true;
1035 Crosshair.On = false;
1037 /* set initial shape */
1038 Crosshair.shape = Basic_Crosshair_Shape;
1040 /* set default limits */
1041 Crosshair.MinX = Crosshair.MinY = 0;
1042 Crosshair.MaxX = PCB->MaxWidth;
1043 Crosshair.MaxY = PCB->MaxHeight;
1045 /* clear the mark */
1046 Marked.status = false;
1049 /* ---------------------------------------------------------------------------
1050 * exits crosshair routines, release GCs
1052 void
1053 DestroyCrosshair (void)
1055 CrosshairOff (true);
1056 FreePolygonMemory (&Crosshair.AttachedPolygon);
1057 gui->destroy_gc (Crosshair.GC);