4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
41 #include "crosshair.h"
51 #ifdef HAVE_LIBDMALLOC
60 /* ---------------------------------------------------------------------------
61 * some local prototypes
63 static void XORPolygon (PolygonType
*, Coord
, Coord
);
64 static void XORDrawElement (ElementType
*, Coord
, Coord
);
65 static void XORDrawBuffer (BufferType
*);
66 static void XORDrawInsertPointObject (void);
67 static void XORDrawMoveOrCopyObject (void);
68 static void XORDrawAttachedLine (Coord
, Coord
, Coord
, Coord
, Coord
);
69 static void XORDrawAttachedArc (Coord
);
72 thindraw_moved_pv (PinType
*pv
, Coord x
, Coord y
)
74 /* Make a copy of the pin structure, moved to the correct position */
75 PinType moved_pv
= *pv
;
79 gui
->graphics
->thindraw_pcb_pv (Crosshair
.GC
, Crosshair
.GC
, &moved_pv
, true, false);
82 /* ---------------------------------------------------------------------------
83 * creates a tmp polygon with coordinates converted to screen system
86 XORPolygon (PolygonType
*polygon
, Coord dx
, Coord dy
)
89 for (i
= 0; i
< polygon
->PointN
; i
++)
91 Cardinal next
= next_contour_point (polygon
, i
);
92 gui
->graphics
->draw_line (Crosshair
.GC
,
93 polygon
->Points
[i
].X
+ dx
,
94 polygon
->Points
[i
].Y
+ dy
,
95 polygon
->Points
[next
].X
+ dx
,
96 polygon
->Points
[next
].Y
+ dy
);
100 /*-----------------------------------------------------------
101 * Draws the outline of an arc
104 XORDrawAttachedArc (Coord thick
)
110 Coord wid
= thick
/ 2;
112 wx
= Crosshair
.X
- Crosshair
.AttachedBox
.Point1
.X
;
113 wy
= Crosshair
.Y
- Crosshair
.AttachedBox
.Point1
.Y
;
114 if (wx
== 0 && wy
== 0)
116 arc
.X
= Crosshair
.AttachedBox
.Point1
.X
;
117 arc
.Y
= Crosshair
.AttachedBox
.Point1
.Y
;
118 if (XOR (Crosshair
.AttachedBox
.otherway
, abs (wy
) > abs (wx
)))
120 arc
.X
= Crosshair
.AttachedBox
.Point1
.X
+ abs (wy
) * SGNZ (wx
);
121 sa
= (wx
>= 0) ? 0 : 180;
123 if (abs (wy
) >= 2 * abs (wx
))
124 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 45 : -45;
127 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 90 : -90;
131 arc
.Y
= Crosshair
.AttachedBox
.Point1
.Y
+ abs (wx
) * SGNZ (wy
);
132 sa
= (wy
>= 0) ? -90 : 90;
134 if (abs (wx
) >= 2 * abs (wy
))
135 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -45 : 45;
138 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -90 : 90;
144 arc
.Width
= arc
.Height
= wy
;
145 bx
= GetArcEnds (&arc
);
147 gui
->graphics
->draw_arc (Crosshair
.GC
, arc
.X
, arc
.Y
, wy
+ wid
, wy
+ wid
, sa
, dir
);
148 if (wid
> pixel_slop
)
150 gui
->graphics
->draw_arc (Crosshair
.GC
, arc
.X
, arc
.Y
, wy
- wid
, wy
- wid
, sa
, dir
);
151 gui
->graphics
->draw_arc (Crosshair
.GC
, bx
->X1
, bx
->Y1
, wid
, wid
, sa
, -180 * SGN (dir
));
152 gui
->graphics
->draw_arc (Crosshair
.GC
, bx
->X2
, bx
->Y2
, wid
, wid
, sa
+ dir
, 180 * SGN (dir
));
156 /*-----------------------------------------------------------
157 * Draws the outline of a line
160 XORDrawAttachedLine (Coord x1
, Coord y1
, Coord x2
, Coord y2
, Coord thick
)
162 Coord dx
, dy
, ox
, oy
;
167 if (dx
!= 0 || dy
!= 0)
168 h
= 0.5 * thick
/ sqrt (SQUARE (dx
) + SQUARE (dy
));
171 ox
= dy
* h
+ 0.5 * SGN (dy
);
172 oy
= -(dx
* h
+ 0.5 * SGN (dx
));
173 gui
->graphics
->draw_line (Crosshair
.GC
, x1
+ ox
, y1
+ oy
, x2
+ ox
, y2
+ oy
);
174 if (abs (ox
) >= pixel_slop
|| abs (oy
) >= pixel_slop
)
176 Angle angle
= atan2 (dx
, dy
) * 57.295779;
177 gui
->graphics
->draw_line (Crosshair
.GC
, x1
- ox
, y1
- oy
, x2
- ox
, y2
- oy
);
178 gui
->graphics
->draw_arc (Crosshair
.GC
, x1
, y1
, thick
/ 2, thick
/ 2, angle
- 180, 180);
179 gui
->graphics
->draw_arc (Crosshair
.GC
, x2
, y2
, thick
/ 2, thick
/ 2, angle
, 180);
183 /* ---------------------------------------------------------------------------
184 * draws the elements of a loaded circuit which is to be merged in
187 XORDrawElement (ElementType
*Element
, Coord DX
, Coord DY
)
189 /* if no silkscreen, draw the bounding box */
190 if (Element
->ArcN
== 0 && Element
->LineN
== 0)
192 gui
->graphics
->draw_line (Crosshair
.GC
,
193 DX
+ Element
->BoundingBox
.X1
,
194 DY
+ Element
->BoundingBox
.Y1
,
195 DX
+ Element
->BoundingBox
.X1
,
196 DY
+ Element
->BoundingBox
.Y2
);
197 gui
->graphics
->draw_line (Crosshair
.GC
,
198 DX
+ Element
->BoundingBox
.X1
,
199 DY
+ Element
->BoundingBox
.Y2
,
200 DX
+ Element
->BoundingBox
.X2
,
201 DY
+ Element
->BoundingBox
.Y2
);
202 gui
->graphics
->draw_line (Crosshair
.GC
,
203 DX
+ Element
->BoundingBox
.X2
,
204 DY
+ Element
->BoundingBox
.Y2
,
205 DX
+ Element
->BoundingBox
.X2
,
206 DY
+ Element
->BoundingBox
.Y1
);
207 gui
->graphics
->draw_line (Crosshair
.GC
,
208 DX
+ Element
->BoundingBox
.X2
,
209 DY
+ Element
->BoundingBox
.Y1
,
210 DX
+ Element
->BoundingBox
.X1
,
211 DY
+ Element
->BoundingBox
.Y1
);
215 ELEMENTLINE_LOOP (Element
);
217 gui
->graphics
->draw_line (Crosshair
.GC
,
221 DY
+ line
->Point2
.Y
);
225 /* arc coordinates and angles have to be converted to X11 notation */
228 gui
->graphics
->draw_arc (Crosshair
.GC
,
231 arc
->Width
, arc
->Height
, arc
->StartAngle
, arc
->Delta
);
235 /* pin coordinates and angles have to be converted to X11 notation */
238 thindraw_moved_pv (pin
, DX
, DY
);
245 if (PCB
->InvisibleObjectsOn
||
246 (TEST_FLAG (ONSOLDERFLAG
, pad
) != 0) == Settings
.ShowBottomSide
)
248 /* Make a copy of the pad structure, moved to the correct position */
249 PadType moved_pad
= *pad
;
250 moved_pad
.Point1
.X
+= DX
; moved_pad
.Point1
.Y
+= DY
;
251 moved_pad
.Point2
.X
+= DX
; moved_pad
.Point2
.Y
+= DY
;
253 gui
->graphics
->thindraw_pcb_pad (Crosshair
.GC
, &moved_pad
, false, false);
258 gui
->graphics
->draw_line (Crosshair
.GC
,
259 Element
->MarkX
+ DX
- EMARK_SIZE
,
262 Element
->MarkY
+ DY
- EMARK_SIZE
);
263 gui
->graphics
->draw_line (Crosshair
.GC
,
264 Element
->MarkX
+ DX
+ EMARK_SIZE
,
267 Element
->MarkY
+ DY
- EMARK_SIZE
);
268 gui
->graphics
->draw_line (Crosshair
.GC
,
269 Element
->MarkX
+ DX
- EMARK_SIZE
,
272 Element
->MarkY
+ DY
+ EMARK_SIZE
);
273 gui
->graphics
->draw_line (Crosshair
.GC
,
274 Element
->MarkX
+ DX
+ EMARK_SIZE
,
277 Element
->MarkY
+ DY
+ EMARK_SIZE
);
280 /* ---------------------------------------------------------------------------
281 * draws all visible and attached objects of the pastebuffer
284 XORDrawBuffer (BufferType
*Buffer
)
290 x
= Crosshair
.X
- Buffer
->X
;
291 y
= Crosshair
.Y
- Buffer
->Y
;
293 /* draw all visible layers */
294 for (i
= 0; i
< max_copper_layer
+ 2; i
++)
295 if (PCB
->Data
->Layer
[i
].On
)
297 LayerType
*layer
= &Buffer
->Data
->Layer
[i
];
302 XORDrawAttachedLine(x +line->Point1.X,
303 y +line->Point1.Y, x +line->Point2.X,
304 y +line->Point2.Y, line->Thickness);
306 gui
->graphics
->draw_line (Crosshair
.GC
,
307 x
+ line
->Point1
.X
, y
+ line
->Point1
.Y
,
308 x
+ line
->Point2
.X
, y
+ line
->Point2
.Y
);
313 gui
->graphics
->draw_arc (Crosshair
.GC
,
317 arc
->Height
, arc
->StartAngle
, arc
->Delta
);
322 BoxType
*box
= &text
->BoundingBox
;
323 gui
->graphics
->draw_rect (Crosshair
.GC
,
324 x
+ box
->X1
, y
+ box
->Y1
, x
+ box
->X2
, y
+ box
->Y2
);
327 /* the tmp polygon has n+1 points because the first
328 * and the last one are set to the same coordinates
330 POLYGON_LOOP (layer
);
332 XORPolygon (polygon
, x
, y
);
337 /* draw elements if visible */
338 if (PCB
->PinOn
&& PCB
->ElementOn
)
339 ELEMENT_LOOP (Buffer
->Data
);
341 if (FRONT (element
) || PCB
->InvisibleObjectsOn
)
342 XORDrawElement (element
, x
, y
);
348 VIA_LOOP (Buffer
->Data
);
350 thindraw_moved_pv (via
, x
, y
);
355 /* ---------------------------------------------------------------------------
356 * draws the rubberband to insert points into polygons/lines/...
359 XORDrawInsertPointObject (void)
361 LineType
*line
= (LineType
*) Crosshair
.AttachedObject
.Ptr2
;
362 PointType
*point
= (PointType
*) Crosshair
.AttachedObject
.Ptr3
;
364 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
366 gui
->graphics
->draw_line (Crosshair
.GC
, point
->X
, point
->Y
, line
->Point1
.X
, line
->Point1
.Y
);
367 gui
->graphics
->draw_line (Crosshair
.GC
, point
->X
, point
->Y
, line
->Point2
.X
, line
->Point2
.Y
);
371 /* ---------------------------------------------------------------------------
372 * draws the attached object while in MOVE_MODE or COPY_MODE
375 XORDrawMoveOrCopyObject (void)
379 Coord dx
= Crosshair
.X
- Crosshair
.AttachedObject
.X
,
380 dy
= Crosshair
.Y
- Crosshair
.AttachedObject
.Y
;
382 switch (Crosshair
.AttachedObject
.Type
)
386 PinType
*via
= (PinType
*) Crosshair
.AttachedObject
.Ptr1
;
387 thindraw_moved_pv (via
, dx
, dy
);
393 LineType
*line
= (LineType
*) Crosshair
.AttachedObject
.Ptr2
;
395 XORDrawAttachedLine (line
->Point1
.X
+ dx
, line
->Point1
.Y
+ dy
,
396 line
->Point2
.X
+ dx
, line
->Point2
.Y
+ dy
,
403 ArcType
*Arc
= (ArcType
*) Crosshair
.AttachedObject
.Ptr2
;
405 gui
->graphics
->draw_arc (Crosshair
.GC
,
408 Arc
->Width
, Arc
->Height
, Arc
->StartAngle
, Arc
->Delta
);
414 PolygonType
*polygon
=
415 (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
;
417 /* the tmp polygon has n+1 points because the first
418 * and the last one are set to the same coordinates
420 XORPolygon (polygon
, dx
, dy
);
429 line
= (LineType
*) Crosshair
.AttachedObject
.Ptr2
;
430 point
= (PointType
*) Crosshair
.AttachedObject
.Ptr3
;
431 if (point
== &line
->Point1
)
432 XORDrawAttachedLine (point
->X
+ dx
,
433 point
->Y
+ dy
, line
->Point2
.X
,
434 line
->Point2
.Y
, line
->Thickness
);
436 XORDrawAttachedLine (point
->X
+ dx
,
437 point
->Y
+ dy
, line
->Point1
.X
,
438 line
->Point1
.Y
, line
->Thickness
);
442 case POLYGONPOINT_TYPE
:
444 PolygonType
*polygon
;
446 Cardinal point_idx
, prev
, next
;
448 polygon
= (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
;
449 point
= (PointType
*) Crosshair
.AttachedObject
.Ptr3
;
450 point_idx
= polygon_point_idx (polygon
, point
);
452 /* get previous and following point */
453 prev
= prev_contour_point (polygon
, point_idx
);
454 next
= next_contour_point (polygon
, point_idx
);
456 /* draw the two segments */
457 gui
->graphics
->draw_line (Crosshair
.GC
,
458 polygon
->Points
[prev
].X
, polygon
->Points
[prev
].Y
,
459 point
->X
+ dx
, point
->Y
+ dy
);
460 gui
->graphics
->draw_line (Crosshair
.GC
,
461 point
->X
+ dx
, point
->Y
+ dy
,
462 polygon
->Points
[next
].X
, polygon
->Points
[next
].Y
);
466 case ELEMENTNAME_TYPE
:
468 /* locate the element "mark" and draw an association line from crosshair to it */
469 ElementType
*element
=
470 (ElementType
*) Crosshair
.AttachedObject
.Ptr1
;
472 gui
->graphics
->draw_line (Crosshair
.GC
,
474 element
->MarkY
, Crosshair
.X
, Crosshair
.Y
);
475 /* fall through to move the text as a box outline */
479 TextType
*text
= (TextType
*) Crosshair
.AttachedObject
.Ptr2
;
480 BoxType
*box
= &text
->BoundingBox
;
481 gui
->graphics
->draw_rect (Crosshair
.GC
,
483 box
->Y1
+ dy
, box
->X2
+ dx
, box
->Y2
+ dy
);
487 /* pin/pad movements result in moving an element */
491 XORDrawElement ((ElementType
*) Crosshair
.AttachedObject
.Ptr2
, dx
, dy
);
495 /* draw the attached rubberband lines too */
496 i
= Crosshair
.AttachedObject
.RubberbandN
;
497 ptr
= Crosshair
.AttachedObject
.Rubberband
;
500 PointType
*point1
, *point2
;
502 if (TEST_FLAG (VIAFLAG
, ptr
->Line
))
504 /* this is a rat going to a polygon. do not draw for rubberband */;
506 else if (TEST_FLAG (RUBBERENDFLAG
, ptr
->Line
))
508 /* 'point1' is always the fix-point */
509 if (ptr
->MovedPoint
== &ptr
->Line
->Point1
)
511 point1
= &ptr
->Line
->Point2
;
512 point2
= &ptr
->Line
->Point1
;
516 point1
= &ptr
->Line
->Point1
;
517 point2
= &ptr
->Line
->Point2
;
519 XORDrawAttachedLine (point1
->X
,
520 point1
->Y
, point2
->X
+ dx
,
521 point2
->Y
+ dy
, ptr
->Line
->Thickness
);
523 else if (ptr
->MovedPoint
== &ptr
->Line
->Point1
)
524 XORDrawAttachedLine (ptr
->Line
->Point1
.X
+ dx
,
525 ptr
->Line
->Point1
.Y
+ dy
,
526 ptr
->Line
->Point2
.X
+ dx
,
527 ptr
->Line
->Point2
.Y
+ dy
, ptr
->Line
->Thickness
);
534 /* ---------------------------------------------------------------------------
535 * draws additional stuff that follows the crosshair
540 switch (Settings
.Mode
)
544 /* Make a dummy via structure to draw from */
548 via
.Thickness
= Settings
.ViaThickness
;
549 via
.Clearance
= 2 * Settings
.Keepaway
;
550 via
.DrillingHole
= Settings
.ViaDrillingHole
;
552 via
.Flags
= NoFlags ();
554 gui
->graphics
->thindraw_pcb_pv (Crosshair
.GC
, Crosshair
.GC
, &via
, true, false);
556 if (TEST_FLAG (SHOWDRCFLAG
, PCB
))
558 /* XXX: Naughty cheat - use the mask to draw DRC clearance! */
559 via
.Mask
= Settings
.ViaThickness
+ PCB
->Bloat
* 2;
560 gui
->graphics
->set_color (Crosshair
.GC
, Settings
.CrossColor
);
561 gui
->graphics
->thindraw_pcb_pv (Crosshair
.GC
, Crosshair
.GC
, &via
, false, true);
562 gui
->graphics
->set_color (Crosshair
.GC
, Settings
.CrosshairColor
);
567 /* the attached line is used by both LINEMODE, POLYGON_MODE and POLYGONHOLE_MODE*/
569 case POLYGONHOLE_MODE
:
570 /* draw only if starting point is set */
571 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
572 gui
->graphics
->draw_line (Crosshair
.GC
,
573 Crosshair
.AttachedLine
.Point1
.X
,
574 Crosshair
.AttachedLine
.Point1
.Y
,
575 Crosshair
.AttachedLine
.Point2
.X
,
576 Crosshair
.AttachedLine
.Point2
.Y
);
578 /* draw attached polygon only if in POLYGON_MODE or POLYGONHOLE_MODE */
579 if (Crosshair
.AttachedPolygon
.PointN
> 1)
581 XORPolygon (&Crosshair
.AttachedPolygon
, 0, 0);
586 if (Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
588 XORDrawAttachedArc (Settings
.LineThickness
);
589 if (TEST_FLAG (SHOWDRCFLAG
, PCB
))
591 gui
->graphics
->set_color (Crosshair
.GC
, Settings
.CrossColor
);
592 XORDrawAttachedArc (Settings
.LineThickness
+
593 2 * (PCB
->Bloat
+ 1));
594 gui
->graphics
->set_color (Crosshair
.GC
, Settings
.CrosshairColor
);
601 /* draw only if starting point exists and the line has length */
602 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
&&
603 Crosshair
.AttachedLine
.draw
)
605 XORDrawAttachedLine (Crosshair
.AttachedLine
.Point1
.X
,
606 Crosshair
.AttachedLine
.Point1
.Y
,
607 Crosshair
.AttachedLine
.Point2
.X
,
608 Crosshair
.AttachedLine
.Point2
.Y
,
609 PCB
->RatDraw
? 10 : Settings
.LineThickness
);
610 /* draw two lines ? */
612 XORDrawAttachedLine (Crosshair
.AttachedLine
.Point2
.X
,
613 Crosshair
.AttachedLine
.Point2
.Y
,
614 Crosshair
.X
, Crosshair
.Y
,
615 PCB
->RatDraw
? 10 : Settings
.LineThickness
);
616 if (TEST_FLAG (SHOWDRCFLAG
, PCB
))
618 gui
->graphics
->set_color (Crosshair
.GC
, Settings
.CrossColor
);
619 XORDrawAttachedLine (Crosshair
.AttachedLine
.Point1
.X
,
620 Crosshair
.AttachedLine
.Point1
.Y
,
621 Crosshair
.AttachedLine
.Point2
.X
,
622 Crosshair
.AttachedLine
.Point2
.Y
,
623 PCB
->RatDraw
? 10 : Settings
.LineThickness
624 + 2 * (PCB
->Bloat
+ 1));
626 XORDrawAttachedLine (Crosshair
.AttachedLine
.Point2
.X
,
627 Crosshair
.AttachedLine
.Point2
.Y
,
628 Crosshair
.X
, Crosshair
.Y
,
629 PCB
->RatDraw
? 10 : Settings
.
630 LineThickness
+ 2 * (PCB
->Bloat
+ 1));
631 gui
->graphics
->set_color (Crosshair
.GC
, Settings
.CrosshairColor
);
636 case PASTEBUFFER_MODE
:
637 XORDrawBuffer (PASTEBUFFER
);
642 XORDrawMoveOrCopyObject ();
645 case INSERTPOINT_MODE
:
646 XORDrawInsertPointObject ();
650 /* an attached box does not depend on a special mode */
651 if (Crosshair
.AttachedBox
.State
== STATE_SECOND
||
652 Crosshair
.AttachedBox
.State
== STATE_THIRD
)
654 Coord x1
, y1
, x2
, y2
;
656 x1
= Crosshair
.AttachedBox
.Point1
.X
;
657 y1
= Crosshair
.AttachedBox
.Point1
.Y
;
658 x2
= Crosshair
.AttachedBox
.Point2
.X
;
659 y2
= Crosshair
.AttachedBox
.Point2
.Y
;
660 gui
->graphics
->draw_rect (Crosshair
.GC
, x1
, y1
, x2
, y2
);
665 /* --------------------------------------------------------------------------
666 * draw the marker position
671 /* Mark is not drawn when it is not set */
675 gui
->graphics
->draw_line (Crosshair
.GC
,
676 Marked
.X
- MARK_SIZE
,
677 Marked
.Y
- MARK_SIZE
,
678 Marked
.X
+ MARK_SIZE
, Marked
.Y
+ MARK_SIZE
);
679 gui
->graphics
->draw_line (Crosshair
.GC
,
680 Marked
.X
+ MARK_SIZE
,
681 Marked
.Y
- MARK_SIZE
,
682 Marked
.X
- MARK_SIZE
, Marked
.Y
+ MARK_SIZE
);
685 /* ---------------------------------------------------------------------------
686 * Returns the nearest grid-point to the given Coord
689 GridFit (Coord x
, Coord grid_spacing
, Coord grid_offset
)
692 x
= grid_spacing
* round ((double) x
/ grid_spacing
);
698 /* ---------------------------------------------------------------------------
699 * notify the GUI that data relating to the crosshair is being changed.
701 * The argument passed is false to notify "changes are about to happen",
702 * and true to notify "changes have finished".
704 * Each call with a 'false' parameter must be matched with a following one
705 * with a 'true' parameter. Unmatched 'true' calls are currently not permitted,
706 * but might be allowed in the future.
708 * GUIs should not complain if they receive extra calls with 'true' as parameter.
709 * They should initiate a redraw of the crosshair attached objects - which may
710 * (if necessary) mean repainting the whole screen if the GUI hasn't tracked the
711 * location of existing attached drawing.
714 notify_crosshair_change (bool changes_complete
)
716 if (gui
->notify_crosshair_change
)
717 gui
->notify_crosshair_change (changes_complete
);
721 /* ---------------------------------------------------------------------------
722 * notify the GUI that data relating to the mark is being changed.
724 * The argument passed is false to notify "changes are about to happen",
725 * and true to notify "changes have finished".
727 * Each call with a 'false' parameter must be matched with a following one
728 * with a 'true' parameter. Unmatched 'true' calls are currently not permitted,
729 * but might be allowed in the future.
731 * GUIs should not complain if they receive extra calls with 'true' as parameter.
732 * They should initiate a redraw of the mark - which may (if necessary) mean
733 * repainting the whole screen if the GUI hasn't tracked the mark's location.
736 notify_mark_change (bool changes_complete
)
738 if (gui
->notify_mark_change
)
739 gui
->notify_mark_change (changes_complete
);
743 /* ---------------------------------------------------------------------------
744 * Convenience for plugins using the old {Hide,Restore}Crosshair API.
745 * This links up to notify the GUI of the expected changes using the new APIs.
747 * Use of this old API is deprecated, as the names don't necessarily reflect
748 * what all GUIs may do in response to the notifications. Keeping these APIs
749 * is aimed at easing transition to the newer API, they will emit a harmless
750 * warning at the time of their first use.
756 static bool warned_old_api
= false;
759 Message (_("WARNING: A plugin is using the deprecated API HideCrosshair().\n"
760 " This API may be removed in a future release of PCB.\n"));
761 warned_old_api
= true;
764 notify_crosshair_change (false);
765 notify_mark_change (false);
769 RestoreCrosshair (void)
771 static bool warned_old_api
= false;
774 Message (_("WARNING: A plugin is using the deprecated API RestoreCrosshair().\n"
775 " This API may be removed in a future release of PCB.\n"));
776 warned_old_api
= true;
779 notify_crosshair_change (true);
780 notify_mark_change (true);
783 /* ---------------------------------------------------------------------------
784 * Returns the square of the given number
793 crosshair_sq_dist (CrosshairType
*crosshair
, Coord x
, Coord y
)
795 return square (x
- crosshair
->X
) + square (y
- crosshair
->Y
);
799 CrosshairType
*crosshair
;
800 double nearest_sq_dist
;
801 bool nearest_is_grid
;
805 /* Snap to a given location if it is the closest thing we found so far.
806 * If "prefer_to_grid" is set, the passed location will take preference
807 * over a closer grid points we already snapped to UNLESS the user is
808 * pressing the SHIFT key. If the SHIFT key is pressed, the closest object
809 * (including grid points), is always preferred.
812 check_snap_object (struct snap_data
*snap_data
, Coord x
, Coord y
,
817 sq_dist
= crosshair_sq_dist (snap_data
->crosshair
, x
, y
);
818 if (sq_dist
<= snap_data
->nearest_sq_dist
||
819 (prefer_to_grid
&& snap_data
->nearest_is_grid
&& !gui
->shift_is_pressed()))
823 snap_data
->nearest_sq_dist
= sq_dist
;
824 snap_data
->nearest_is_grid
= false;
829 check_snap_offgrid_line (struct snap_data
*snap_data
,
830 Coord nearest_grid_x
,
831 Coord nearest_grid_y
)
833 void *ptr1
, *ptr2
, *ptr3
;
840 if (!TEST_FLAG (SNAPPINFLAG
, PCB
))
843 /* Code to snap at some sensible point along a line */
844 /* Pick the nearest grid-point in the x or y direction
845 * to align with, then adjust until we hit the line
847 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
848 LINE_TYPE
, &ptr1
, &ptr2
, &ptr3
);
853 line
= (LineType
*)ptr2
;
855 /* Allow snapping to off-grid lines when drawing new lines (on
856 * the same layer), and when moving a line end-point
857 * (but don't snap to the same line)
859 if ((Settings
.Mode
!= LINE_MODE
|| CURRENT
!= ptr1
) &&
860 (Settings
.Mode
!= MOVE_MODE
||
861 Crosshair
.AttachedObject
.Ptr1
!= ptr1
||
862 Crosshair
.AttachedObject
.Type
!= LINEPOINT_TYPE
||
863 Crosshair
.AttachedObject
.Ptr2
== line
))
866 dx
= line
->Point2
.X
- line
->Point1
.X
;
867 dy
= line
->Point2
.Y
- line
->Point1
.Y
;
869 /* Try snapping along the X axis */
872 /* Move in the X direction until we hit the line */
873 try_x
= (nearest_grid_y
- line
->Point1
.Y
) / dy
* dx
+ line
->Point1
.X
;
874 try_y
= nearest_grid_y
;
875 check_snap_object (snap_data
, try_x
, try_y
, true);
878 /* Try snapping along the Y axis */
881 try_x
= nearest_grid_x
;
882 try_y
= (nearest_grid_x
- line
->Point1
.X
) / dx
* dy
+ line
->Point1
.Y
;
883 check_snap_object (snap_data
, try_x
, try_y
, true);
886 if (dx
!= dy
) /* If line not parallel with dX = dY direction.. */
888 /* Try snapping diagonally towards the line in the dX = dY direction */
891 dist
= line
->Point1
.Y
- nearest_grid_y
;
893 dist
= ((line
->Point1
.X
- nearest_grid_x
) -
894 (line
->Point1
.Y
- nearest_grid_y
) * dx
/ dy
) / (1 - dx
/ dy
);
896 try_x
= nearest_grid_x
+ dist
;
897 try_y
= nearest_grid_y
+ dist
;
899 check_snap_object (snap_data
, try_x
, try_y
, true);
902 if (dx
!= -dy
) /* If line not parallel with dX = -dY direction.. */
904 /* Try snapping diagonally towards the line in the dX = -dY direction */
907 dist
= nearest_grid_y
- line
->Point1
.Y
;
909 dist
= ((line
->Point1
.X
- nearest_grid_x
) -
910 (line
->Point1
.Y
- nearest_grid_y
) * dx
/ dy
) / (1 + dx
/ dy
);
912 try_x
= nearest_grid_x
+ dist
;
913 try_y
= nearest_grid_y
- dist
;
915 check_snap_object (snap_data
, try_x
, try_y
, true);
919 /* ---------------------------------------------------------------------------
920 * recalculates the passed coordinates to fit the current grid setting
923 FitCrosshairIntoGrid (Coord X
, Coord Y
)
925 Coord nearest_grid_x
, nearest_grid_y
;
926 void *ptr1
, *ptr2
, *ptr3
;
927 struct snap_data snap_data
;
930 Crosshair
.X
= CLAMP (X
, Crosshair
.MinX
, Crosshair
.MaxX
);
931 Crosshair
.Y
= CLAMP (Y
, Crosshair
.MinY
, Crosshair
.MaxY
);
935 nearest_grid_x
= -MIL_TO_COORD (6);
936 nearest_grid_y
= -MIL_TO_COORD (6);
940 nearest_grid_x
= GridFit (Crosshair
.X
, PCB
->Grid
, PCB
->GridOffsetX
);
941 nearest_grid_y
= GridFit (Crosshair
.Y
, PCB
->Grid
, PCB
->GridOffsetY
);
943 if (Marked
.status
&& TEST_FLAG (ORTHOMOVEFLAG
, PCB
))
945 Coord dx
= Crosshair
.X
- Marked
.X
;
946 Coord dy
= Crosshair
.Y
- Marked
.Y
;
947 if (ABS (dx
) > ABS (dy
))
948 nearest_grid_y
= Marked
.Y
;
950 nearest_grid_x
= Marked
.X
;
955 snap_data
.crosshair
= &Crosshair
;
956 snap_data
.nearest_sq_dist
=
957 crosshair_sq_dist (&Crosshair
, nearest_grid_x
, nearest_grid_y
);
958 snap_data
.nearest_is_grid
= true;
959 snap_data
.x
= nearest_grid_x
;
960 snap_data
.y
= nearest_grid_y
;
964 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
965 ELEMENT_TYPE
, &ptr1
, &ptr2
, &ptr3
);
967 if (ans
& ELEMENT_TYPE
)
969 ElementType
*el
= (ElementType
*) ptr1
;
970 check_snap_object (&snap_data
, el
->MarkX
, el
->MarkY
, false);
974 if (PCB
->RatDraw
|| TEST_FLAG (SNAPPINFLAG
, PCB
))
975 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
976 PAD_TYPE
, &ptr1
, &ptr2
, &ptr3
);
978 /* Avoid self-snapping when moving */
979 if (ans
!= NO_TYPE
&&
980 Settings
.Mode
== MOVE_MODE
&&
981 Crosshair
.AttachedObject
.Type
== ELEMENT_TYPE
&&
982 ptr1
== Crosshair
.AttachedObject
.Ptr1
)
985 if (ans
!= NO_TYPE
&&
986 ( Settings
.Mode
== LINE_MODE
||
987 (Settings
.Mode
== MOVE_MODE
&&
988 Crosshair
.AttachedObject
.Type
== LINEPOINT_TYPE
)))
990 PadType
*pad
= (PadType
*) ptr2
;
991 LayerType
*desired_layer
;
992 Cardinal desired_group
;
993 Cardinal bottom_group
, top_group
;
994 int found_our_layer
= false;
996 desired_layer
= CURRENT
;
997 if (Settings
.Mode
== MOVE_MODE
&&
998 Crosshair
.AttachedObject
.Type
== LINEPOINT_TYPE
)
1000 desired_layer
= (LayerType
*)Crosshair
.AttachedObject
.Ptr1
;
1003 /* find layer groups of the top and bottom sides */
1004 top_group
= GetLayerGroupNumberBySide (TOP_SIDE
);
1005 bottom_group
= GetLayerGroupNumberBySide (BOTTOM_SIDE
);
1006 desired_group
= TEST_FLAG (ONSOLDERFLAG
, pad
) ? bottom_group
: top_group
;
1008 GROUP_LOOP (PCB
->Data
, desired_group
);
1010 if (layer
== desired_layer
)
1012 found_our_layer
= true;
1018 if (found_our_layer
== false)
1024 PadType
*pad
= (PadType
*)ptr2
;
1025 check_snap_object (&snap_data
, pad
->Point1
.X
+ (pad
->Point2
.X
- pad
->Point1
.X
) / 2,
1026 pad
->Point1
.Y
+ (pad
->Point2
.Y
- pad
->Point1
.Y
) / 2,
1031 if (PCB
->RatDraw
|| TEST_FLAG (SNAPPINFLAG
, PCB
))
1032 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
1033 PIN_TYPE
, &ptr1
, &ptr2
, &ptr3
);
1035 /* Avoid self-snapping when moving */
1036 if (ans
!= NO_TYPE
&&
1037 Settings
.Mode
== MOVE_MODE
&&
1038 Crosshair
.AttachedObject
.Type
== ELEMENT_TYPE
&&
1039 ptr1
== Crosshair
.AttachedObject
.Ptr1
)
1044 PinType
*pin
= (PinType
*)ptr2
;
1045 check_snap_object (&snap_data
, pin
->X
, pin
->Y
, true);
1049 if (TEST_FLAG (SNAPPINFLAG
, PCB
))
1050 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
1051 VIA_TYPE
, &ptr1
, &ptr2
, &ptr3
);
1053 /* Avoid snapping vias to any other vias */
1054 if (Settings
.Mode
== MOVE_MODE
&&
1055 Crosshair
.AttachedObject
.Type
== VIA_TYPE
&&
1061 PinType
*pin
= (PinType
*)ptr2
;
1062 check_snap_object (&snap_data
, pin
->X
, pin
->Y
, true);
1066 if (TEST_FLAG (SNAPPINFLAG
, PCB
))
1067 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
1068 LINEPOINT_TYPE
| ARCPOINT_TYPE
,
1069 &ptr1
, &ptr2
, &ptr3
);
1073 PointType
*pnt
= (PointType
*)ptr3
;
1074 check_snap_object (&snap_data
, pnt
->X
, pnt
->Y
, true);
1077 check_snap_offgrid_line (&snap_data
, nearest_grid_x
, nearest_grid_y
);
1080 if (TEST_FLAG (SNAPPINFLAG
, PCB
))
1081 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
1082 POLYGONPOINT_TYPE
, &ptr1
, &ptr2
, &ptr3
);
1086 PointType
*pnt
= (PointType
*)ptr3
;
1087 check_snap_object (&snap_data
, pnt
->X
, pnt
->Y
, true);
1090 if (snap_data
.x
>= 0 && snap_data
.y
>= 0)
1092 Crosshair
.X
= snap_data
.x
;
1093 Crosshair
.Y
= snap_data
.y
;
1096 if (Settings
.Mode
== ARROW_MODE
)
1098 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
1099 LINEPOINT_TYPE
| ARCPOINT_TYPE
,
1100 &ptr1
, &ptr2
, &ptr3
);
1102 hid_action("PointCursor");
1103 else if (!TEST_FLAG(SELECTEDFLAG
, (LineType
*)ptr2
))
1104 hid_actionl("PointCursor","True", NULL
);
1107 if (Settings
.Mode
== LINE_MODE
1108 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
1109 && TEST_FLAG (AUTODRCFLAG
, PCB
))
1112 gui
->set_crosshair (Crosshair
.X
, Crosshair
.Y
, HID_SC_DO_NOTHING
);
1115 /* ---------------------------------------------------------------------------
1116 * move crosshair absolute
1117 * return true if the crosshair was moved from its existing position
1120 MoveCrosshairAbsolute (Coord X
, Coord Y
)
1122 Coord old_x
= Crosshair
.X
;
1123 Coord old_y
= Crosshair
.Y
;
1125 FitCrosshairIntoGrid (X
, Y
);
1127 if (Crosshair
.X
!= old_x
|| Crosshair
.Y
!= old_y
)
1129 Coord new_x
= Crosshair
.X
;
1130 Coord new_y
= Crosshair
.Y
;
1132 /* back up to old position to notify the GUI
1133 * (which might want to erase the old crosshair) */
1134 Crosshair
.X
= old_x
;
1135 Crosshair
.Y
= old_y
;
1136 notify_crosshair_change (false); /* Our caller notifies when it has done */
1138 /* now move forward again */
1139 Crosshair
.X
= new_x
;
1140 Crosshair
.Y
= new_y
;
1146 /* ---------------------------------------------------------------------------
1147 * sets the valid range for the crosshair cursor
1150 SetCrosshairRange (Coord MinX
, Coord MinY
, Coord MaxX
, Coord MaxY
)
1152 Crosshair
.MinX
= MAX (0, MinX
);
1153 Crosshair
.MinY
= MAX (0, MinY
);
1154 Crosshair
.MaxX
= MIN (PCB
->MaxWidth
, MaxX
);
1155 Crosshair
.MaxY
= MIN (PCB
->MaxHeight
, MaxY
);
1157 /* force update of position */
1158 FitCrosshairIntoGrid (Crosshair
.X
, Crosshair
.Y
);
1161 /* ---------------------------------------------------------------------------
1162 * initializes crosshair stuff
1163 * clears the struct, allocates to graphical contexts
1166 InitCrosshair (void)
1168 Crosshair
.GC
= gui
->graphics
->make_gc ();
1170 gui
->graphics
->set_color (Crosshair
.GC
, Settings
.CrosshairColor
);
1171 gui
->graphics
->set_draw_xor (Crosshair
.GC
, 1);
1172 gui
->graphics
->set_line_cap (Crosshair
.GC
, Trace_Cap
);
1173 gui
->graphics
->set_line_width (Crosshair
.GC
, 1);
1175 /* set initial shape */
1176 Crosshair
.shape
= Basic_Crosshair_Shape
;
1178 /* set default limits */
1179 Crosshair
.MinX
= Crosshair
.MinY
= 0;
1180 Crosshair
.MaxX
= PCB
->MaxWidth
;
1181 Crosshair
.MaxY
= PCB
->MaxHeight
;
1183 /* clear the mark */
1184 Marked
.status
= false;
1187 /* ---------------------------------------------------------------------------
1188 * exits crosshair routines, release GCs
1191 DestroyCrosshair (void)
1193 FreePolygonMemory (&Crosshair
.AttachedPolygon
);
1194 gui
->graphics
->destroy_gc (Crosshair
.GC
);