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
62 thindraw_moved_pv (hidGC gc
, PinType
*pv
, Coord x
, Coord y
)
64 /* Make a copy of the pin structure, moved to the correct position */
65 PinType moved_pv
= *pv
;
69 hid_draw_thin_pcb_pv (gc
, gc
, &moved_pv
, true, false);
72 /* ---------------------------------------------------------------------------
73 * creates a tmp polygon with coordinates converted to screen system
76 XORPolygon (hidGC gc
, PolygonType
*polygon
, Coord dx
, Coord dy
)
79 for (i
= 0; i
< polygon
->PointN
; i
++)
81 Cardinal next
= next_contour_point (polygon
, i
);
82 hid_draw_line (gc
, polygon
->Points
[i
].X
+ dx
,
83 polygon
->Points
[i
].Y
+ dy
,
84 polygon
->Points
[next
].X
+ dx
,
85 polygon
->Points
[next
].Y
+ dy
);
89 /*-----------------------------------------------------------
90 * Draws the outline of an arc
93 XORDrawAttachedArc (hidGC gc
, Coord thick
)
99 Coord wid
= thick
/ 2;
101 wx
= Crosshair
.X
- Crosshair
.AttachedBox
.Point1
.X
;
102 wy
= Crosshair
.Y
- Crosshair
.AttachedBox
.Point1
.Y
;
103 if (wx
== 0 && wy
== 0)
105 arc
.X
= Crosshair
.AttachedBox
.Point1
.X
;
106 arc
.Y
= Crosshair
.AttachedBox
.Point1
.Y
;
107 if (XOR (Crosshair
.AttachedBox
.otherway
, abs (wy
) > abs (wx
)))
109 arc
.X
= Crosshair
.AttachedBox
.Point1
.X
+ abs (wy
) * SGNZ (wx
);
110 sa
= (wx
>= 0) ? 0 : 180;
112 if (abs (wy
) >= 2 * abs (wx
))
113 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 45 : -45;
116 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 90 : -90;
120 arc
.Y
= Crosshair
.AttachedBox
.Point1
.Y
+ abs (wx
) * SGNZ (wy
);
121 sa
= (wy
>= 0) ? -90 : 90;
123 if (abs (wx
) >= 2 * abs (wy
))
124 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -45 : 45;
127 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -90 : 90;
133 arc
.Width
= arc
.Height
= wy
;
134 bx
= GetArcEnds (&arc
);
136 hid_draw_arc (gc
, arc
.X
, arc
.Y
, wy
+ wid
, wy
+ wid
, sa
, dir
);
137 if (wid
> pixel_slop
)
139 hid_draw_arc (gc
, arc
.X
, arc
.Y
, wy
- wid
, wy
- wid
, sa
, dir
);
140 hid_draw_arc (gc
, bx
->X1
, bx
->Y1
, wid
, wid
, sa
, -180 * SGN (dir
));
141 hid_draw_arc (gc
, bx
->X2
, bx
->Y2
, wid
, wid
, sa
+ dir
, 180 * SGN (dir
));
145 /*-----------------------------------------------------------
146 * Draws the outline of a line
149 XORDrawAttachedLine (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
, Coord thick
)
151 Coord dx
, dy
, ox
, oy
;
156 if (dx
!= 0 || dy
!= 0)
157 h
= 0.5 * thick
/ sqrt (SQUARE (dx
) + SQUARE (dy
));
160 ox
= dy
* h
+ 0.5 * SGN (dy
);
161 oy
= -(dx
* h
+ 0.5 * SGN (dx
));
162 hid_draw_line (gc
, x1
+ ox
, y1
+ oy
, x2
+ ox
, y2
+ oy
);
163 if (abs (ox
) >= pixel_slop
|| abs (oy
) >= pixel_slop
)
165 Angle angle
= atan2 (dx
, dy
) * 57.295779;
166 hid_draw_line (gc
, x1
- ox
, y1
- oy
, x2
- ox
, y2
- oy
);
167 hid_draw_arc (gc
, x1
, y1
, thick
/ 2, thick
/ 2, angle
- 180, 180);
168 hid_draw_arc (gc
, x2
, y2
, thick
/ 2, thick
/ 2, angle
, 180);
172 /* ---------------------------------------------------------------------------
173 * draws the elements of a loaded circuit which is to be merged in
176 XORDrawElement (hidGC gc
, ElementType
*Element
, Coord DX
, Coord DY
)
178 /* if no silkscreen, draw the bounding box */
179 if (Element
->ArcN
== 0 && Element
->LineN
== 0)
181 hid_draw_line (gc
, DX
+ Element
->BoundingBox
.X1
,
182 DY
+ Element
->BoundingBox
.Y1
,
183 DX
+ Element
->BoundingBox
.X1
,
184 DY
+ Element
->BoundingBox
.Y2
);
185 hid_draw_line (gc
, DX
+ Element
->BoundingBox
.X1
,
186 DY
+ Element
->BoundingBox
.Y2
,
187 DX
+ Element
->BoundingBox
.X2
,
188 DY
+ Element
->BoundingBox
.Y2
);
189 hid_draw_line (gc
, DX
+ Element
->BoundingBox
.X2
,
190 DY
+ Element
->BoundingBox
.Y2
,
191 DX
+ Element
->BoundingBox
.X2
,
192 DY
+ Element
->BoundingBox
.Y1
);
193 hid_draw_line (gc
, DX
+ Element
->BoundingBox
.X2
,
194 DY
+ Element
->BoundingBox
.Y1
,
195 DX
+ Element
->BoundingBox
.X1
,
196 DY
+ Element
->BoundingBox
.Y1
);
200 ELEMENTLINE_LOOP (Element
);
202 hid_draw_line (gc
, DX
+ line
->Point1
.X
,
205 DY
+ line
->Point2
.Y
);
209 /* arc coordinates and angles have to be converted to X11 notation */
212 hid_draw_arc (gc
, DX
+ arc
->X
,
214 arc
->Width
, arc
->Height
, arc
->StartAngle
, arc
->Delta
);
218 /* pin coordinates and angles have to be converted to X11 notation */
221 thindraw_moved_pv (gc
, pin
, DX
, DY
);
228 if (PCB
->InvisibleObjectsOn
||
229 (TEST_FLAG (ONSOLDERFLAG
, pad
) != 0) == Settings
.ShowBottomSide
)
231 /* Make a copy of the pad structure, moved to the correct position */
232 PadType moved_pad
= *pad
;
233 moved_pad
.Point1
.X
+= DX
; moved_pad
.Point1
.Y
+= DY
;
234 moved_pad
.Point2
.X
+= DX
; moved_pad
.Point2
.Y
+= DY
;
236 hid_draw_thin_pcb_pad (gc
, &moved_pad
, false, false);
241 hid_draw_line (gc
, Element
->MarkX
+ DX
- EMARK_SIZE
,
244 Element
->MarkY
+ DY
- EMARK_SIZE
);
245 hid_draw_line (gc
, Element
->MarkX
+ DX
+ EMARK_SIZE
,
248 Element
->MarkY
+ DY
- EMARK_SIZE
);
249 hid_draw_line (gc
, Element
->MarkX
+ DX
- EMARK_SIZE
,
252 Element
->MarkY
+ DY
+ EMARK_SIZE
);
253 hid_draw_line (gc
, Element
->MarkX
+ DX
+ EMARK_SIZE
,
256 Element
->MarkY
+ DY
+ EMARK_SIZE
);
259 /* ---------------------------------------------------------------------------
260 * draws all visible and attached objects of the pastebuffer
263 XORDrawBuffer (hidGC gc
, BufferType
*Buffer
)
269 x
= Crosshair
.X
- Buffer
->X
;
270 y
= Crosshair
.Y
- Buffer
->Y
;
272 /* draw all visible layers */
273 for (i
= 0; i
< max_copper_layer
+ 2; i
++)
274 if (PCB
->Data
->Layer
[i
].On
)
276 LayerType
*layer
= &Buffer
->Data
->Layer
[i
];
281 XORDrawAttachedLine(x +line->Point1.X,
282 y +line->Point1.Y, x +line->Point2.X,
283 y +line->Point2.Y, line->Thickness);
285 hid_draw_line (gc
, x
+ line
->Point1
.X
, y
+ line
->Point1
.Y
,
286 x
+ line
->Point2
.X
, y
+ line
->Point2
.Y
);
291 hid_draw_arc (gc
, x
+ arc
->X
,
293 arc
->Width
, arc
->Height
, arc
->StartAngle
, arc
->Delta
);
298 BoxType
*box
= &text
->BoundingBox
;
299 hid_draw_rect (gc
, x
+ box
->X1
, y
+ box
->Y1
, x
+ box
->X2
, y
+ box
->Y2
);
302 /* the tmp polygon has n+1 points because the first
303 * and the last one are set to the same coordinates
305 POLYGON_LOOP (layer
);
307 XORPolygon (gc
, polygon
, x
, y
);
312 /* draw elements if visible */
313 if (PCB
->PinOn
&& PCB
->ElementOn
)
314 ELEMENT_LOOP (Buffer
->Data
);
316 if (FRONT (element
) || PCB
->InvisibleObjectsOn
)
317 XORDrawElement (gc
, element
, x
, y
);
323 VIA_LOOP (Buffer
->Data
);
325 thindraw_moved_pv (gc
, via
, x
, y
);
330 /* ---------------------------------------------------------------------------
331 * draws the rubberband to insert points into polygons/lines/...
334 XORDrawInsertPointObject (hidGC gc
)
336 LineType
*line
= (LineType
*) Crosshair
.AttachedObject
.Ptr2
;
337 PointType
*point
= (PointType
*) Crosshair
.AttachedObject
.Ptr3
;
339 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
341 hid_draw_line (gc
, point
->X
, point
->Y
, line
->Point1
.X
, line
->Point1
.Y
);
342 hid_draw_line (gc
, point
->X
, point
->Y
, line
->Point2
.X
, line
->Point2
.Y
);
346 /* ---------------------------------------------------------------------------
347 * draws the attached object while in MOVE_MODE or COPY_MODE
350 XORDrawMoveOrCopyObject (hidGC gc
)
354 Coord dx
= Crosshair
.X
- Crosshair
.AttachedObject
.X
,
355 dy
= Crosshair
.Y
- Crosshair
.AttachedObject
.Y
;
357 switch (Crosshair
.AttachedObject
.Type
)
361 PinType
*via
= (PinType
*) Crosshair
.AttachedObject
.Ptr1
;
362 thindraw_moved_pv (gc
, via
, dx
, dy
);
368 LineType
*line
= (LineType
*) Crosshair
.AttachedObject
.Ptr2
;
370 XORDrawAttachedLine (gc
, line
->Point1
.X
+ dx
, line
->Point1
.Y
+ dy
,
371 line
->Point2
.X
+ dx
, line
->Point2
.Y
+ dy
,
378 ArcType
*Arc
= (ArcType
*) Crosshair
.AttachedObject
.Ptr2
;
380 hid_draw_arc (gc
, Arc
->X
+ dx
,
382 Arc
->Width
, Arc
->Height
, Arc
->StartAngle
, Arc
->Delta
);
388 PolygonType
*polygon
=
389 (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
;
391 /* the tmp polygon has n+1 points because the first
392 * and the last one are set to the same coordinates
394 XORPolygon (gc
, polygon
, dx
, dy
);
403 line
= (LineType
*) Crosshair
.AttachedObject
.Ptr2
;
404 point
= (PointType
*) Crosshair
.AttachedObject
.Ptr3
;
405 if (point
== &line
->Point1
)
406 XORDrawAttachedLine (gc
, point
->X
+ dx
, point
->Y
+ dy
,
407 line
->Point2
.X
, line
->Point2
.Y
, line
->Thickness
);
409 XORDrawAttachedLine (gc
, point
->X
+ dx
, point
->Y
+ dy
,
410 line
->Point1
.X
, line
->Point1
.Y
, line
->Thickness
);
414 case POLYGONPOINT_TYPE
:
416 PolygonType
*polygon
;
418 Cardinal point_idx
, prev
, next
;
420 polygon
= (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
;
421 point
= (PointType
*) Crosshair
.AttachedObject
.Ptr3
;
422 point_idx
= polygon_point_idx (polygon
, point
);
424 /* get previous and following point */
425 prev
= prev_contour_point (polygon
, point_idx
);
426 next
= next_contour_point (polygon
, point_idx
);
428 /* draw the two segments */
429 hid_draw_line (gc
, polygon
->Points
[prev
].X
, polygon
->Points
[prev
].Y
,
430 point
->X
+ dx
, point
->Y
+ dy
);
431 hid_draw_line (gc
, point
->X
+ dx
, point
->Y
+ dy
,
432 polygon
->Points
[next
].X
, polygon
->Points
[next
].Y
);
436 case ELEMENTNAME_TYPE
:
438 /* locate the element "mark" and draw an association line from crosshair to it */
439 ElementType
*element
=
440 (ElementType
*) Crosshair
.AttachedObject
.Ptr1
;
442 hid_draw_line (gc
, element
->MarkX
, element
->MarkY
,
443 Crosshair
.X
, Crosshair
.Y
);
444 /* fall through to move the text as a box outline */
448 TextType
*text
= (TextType
*) Crosshair
.AttachedObject
.Ptr2
;
449 BoxType
*box
= &text
->BoundingBox
;
450 hid_draw_rect (gc
, box
->X1
+ dx
, box
->Y1
+ dy
, box
->X2
+ dx
, box
->Y2
+ dy
);
454 /* pin/pad movements result in moving an element */
458 XORDrawElement (gc
, (ElementType
*) Crosshair
.AttachedObject
.Ptr2
, dx
, dy
);
462 /* draw the attached rubberband lines too */
463 i
= Crosshair
.AttachedObject
.RubberbandN
;
464 ptr
= Crosshair
.AttachedObject
.Rubberband
;
467 PointType
*point1
, *point2
;
469 if (TEST_FLAG (VIAFLAG
, ptr
->Line
))
471 /* this is a rat going to a polygon. do not draw for rubberband */;
473 else if (TEST_FLAG (RUBBERENDFLAG
, ptr
->Line
))
475 /* 'point1' is always the fix-point */
476 if (ptr
->MovedPoint
== &ptr
->Line
->Point1
)
478 point1
= &ptr
->Line
->Point2
;
479 point2
= &ptr
->Line
->Point1
;
483 point1
= &ptr
->Line
->Point1
;
484 point2
= &ptr
->Line
->Point2
;
486 XORDrawAttachedLine (gc
, point1
->X
, point1
->Y
,
487 point2
->X
+ dx
, point2
->Y
+ dy
,
488 ptr
->Line
->Thickness
);
490 else if (ptr
->MovedPoint
== &ptr
->Line
->Point1
)
491 XORDrawAttachedLine (gc
,
492 ptr
->Line
->Point1
.X
+ dx
,
493 ptr
->Line
->Point1
.Y
+ dy
,
494 ptr
->Line
->Point2
.X
+ dx
,
495 ptr
->Line
->Point2
.Y
+ dy
, ptr
->Line
->Thickness
);
502 /* ---------------------------------------------------------------------------
503 * draws additional stuff that follows the crosshair
506 DrawAttached (hidGC gc
)
508 hid_draw_set_color (gc
, Settings
.CrosshairColor
);
509 hid_draw_set_draw_xor (gc
, 1);
510 hid_draw_set_line_cap (gc
, Trace_Cap
);
511 hid_draw_set_line_width (gc
, 1);
513 switch (Settings
.Mode
)
517 /* Make a dummy via structure to draw from */
521 via
.Thickness
= Settings
.ViaThickness
;
522 via
.Clearance
= 2 * Settings
.Keepaway
;
523 via
.DrillingHole
= Settings
.ViaDrillingHole
;
525 via
.Flags
= NoFlags ();
527 hid_draw_thin_pcb_pv (gc
, gc
, &via
, true, false);
529 if (TEST_FLAG (SHOWDRCFLAG
, PCB
))
531 Coord mask_r
= Settings
.ViaThickness
/ 2 + PCB
->Bloat
;
532 hid_draw_set_color (gc
, Settings
.CrossColor
);
533 hid_draw_set_line_cap (gc
, Round_Cap
);
534 hid_draw_set_line_width (gc
, 0);
535 hid_draw_arc (gc
, via
.X
, via
.Y
, mask_r
, mask_r
, 0, 360);
536 hid_draw_set_color (gc
, Settings
.CrosshairColor
);
541 /* the attached line is used by both LINEMODE, POLYGON_MODE and POLYGONHOLE_MODE*/
543 case POLYGONHOLE_MODE
:
544 /* draw only if starting point is set */
545 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
546 hid_draw_line (gc
, Crosshair
.AttachedLine
.Point1
.X
,
547 Crosshair
.AttachedLine
.Point1
.Y
,
548 Crosshair
.AttachedLine
.Point2
.X
,
549 Crosshair
.AttachedLine
.Point2
.Y
);
551 /* draw attached polygon only if in POLYGON_MODE or POLYGONHOLE_MODE */
552 if (Crosshair
.AttachedPolygon
.PointN
> 1)
554 XORPolygon (gc
, &Crosshair
.AttachedPolygon
, 0, 0);
559 if (Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
561 XORDrawAttachedArc (gc
, Settings
.LineThickness
);
562 if (TEST_FLAG (SHOWDRCFLAG
, PCB
))
564 hid_draw_set_color (gc
, Settings
.CrossColor
);
565 XORDrawAttachedArc (gc
, Settings
.LineThickness
+ 2 * (PCB
->Bloat
+ 1));
566 hid_draw_set_color (gc
, Settings
.CrosshairColor
);
573 /* draw only if starting point exists and the line has length */
574 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
&&
575 Crosshair
.AttachedLine
.draw
)
577 XORDrawAttachedLine (gc
, Crosshair
.AttachedLine
.Point1
.X
,
578 Crosshair
.AttachedLine
.Point1
.Y
,
579 Crosshair
.AttachedLine
.Point2
.X
,
580 Crosshair
.AttachedLine
.Point2
.Y
,
581 PCB
->RatDraw
? 10 : Settings
.LineThickness
);
582 /* draw two lines ? */
584 XORDrawAttachedLine (gc
, Crosshair
.AttachedLine
.Point2
.X
,
585 Crosshair
.AttachedLine
.Point2
.Y
,
586 Crosshair
.X
, Crosshair
.Y
,
587 PCB
->RatDraw
? 10 : Settings
.LineThickness
);
588 if (TEST_FLAG (SHOWDRCFLAG
, PCB
))
590 hid_draw_set_color (gc
, Settings
.CrossColor
);
591 XORDrawAttachedLine (gc
, Crosshair
.AttachedLine
.Point1
.X
,
592 Crosshair
.AttachedLine
.Point1
.Y
,
593 Crosshair
.AttachedLine
.Point2
.X
,
594 Crosshair
.AttachedLine
.Point2
.Y
,
595 PCB
->RatDraw
? 10 : Settings
.LineThickness
596 + 2 * (PCB
->Bloat
+ 1));
598 XORDrawAttachedLine (gc
, Crosshair
.AttachedLine
.Point2
.X
,
599 Crosshair
.AttachedLine
.Point2
.Y
,
600 Crosshair
.X
, Crosshair
.Y
,
601 PCB
->RatDraw
? 10 : Settings
.
602 LineThickness
+ 2 * (PCB
->Bloat
+ 1));
603 hid_draw_set_color (gc
, Settings
.CrosshairColor
);
608 case PASTEBUFFER_MODE
:
609 XORDrawBuffer (gc
, PASTEBUFFER
);
614 XORDrawMoveOrCopyObject (gc
);
617 case INSERTPOINT_MODE
:
618 XORDrawInsertPointObject (gc
);
622 /* an attached box does not depend on a special mode */
623 if (Crosshair
.AttachedBox
.State
== STATE_SECOND
||
624 Crosshair
.AttachedBox
.State
== STATE_THIRD
)
626 Coord x1
, y1
, x2
, y2
;
628 x1
= Crosshair
.AttachedBox
.Point1
.X
;
629 y1
= Crosshair
.AttachedBox
.Point1
.Y
;
630 x2
= Crosshair
.AttachedBox
.Point2
.X
;
631 y2
= Crosshair
.AttachedBox
.Point2
.Y
;
632 hid_draw_rect (gc
, x1
, y1
, x2
, y2
);
637 /* --------------------------------------------------------------------------
638 * draw the marker position
643 hid_draw_set_color (gc
, Settings
.CrosshairColor
);
644 hid_draw_set_draw_xor (gc
, 1);
645 hid_draw_set_line_cap (gc
, Trace_Cap
);
646 hid_draw_set_line_width (gc
, 1);
648 /* Mark is not drawn when it is not set */
652 hid_draw_line (gc
, Marked
.X
- MARK_SIZE
, Marked
.Y
- MARK_SIZE
,
653 Marked
.X
+ MARK_SIZE
, Marked
.Y
+ MARK_SIZE
);
654 hid_draw_line (gc
, Marked
.X
+ MARK_SIZE
, Marked
.Y
- MARK_SIZE
,
655 Marked
.X
- MARK_SIZE
, Marked
.Y
+ MARK_SIZE
);
658 /* ---------------------------------------------------------------------------
659 * Returns the nearest grid-point to the given Coord
662 GridFit (Coord x
, Coord grid_spacing
, Coord grid_offset
)
665 x
= grid_spacing
* round ((double) x
/ grid_spacing
);
671 /* ---------------------------------------------------------------------------
672 * notify the GUI that data relating to the crosshair is being changed.
674 * The argument passed is false to notify "changes are about to happen",
675 * and true to notify "changes have finished".
677 * Each call with a 'false' parameter must be matched with a following one
678 * with a 'true' parameter. Unmatched 'true' calls are currently not permitted,
679 * but might be allowed in the future.
681 * GUIs should not complain if they receive extra calls with 'true' as parameter.
682 * They should initiate a redraw of the crosshair attached objects - which may
683 * (if necessary) mean repainting the whole screen if the GUI hasn't tracked the
684 * location of existing attached drawing.
687 notify_crosshair_change (bool changes_complete
)
689 if (gui
->notify_crosshair_change
)
690 gui
->notify_crosshair_change (changes_complete
);
694 /* ---------------------------------------------------------------------------
695 * notify the GUI that data relating to the mark is being changed.
697 * The argument passed is false to notify "changes are about to happen",
698 * and true to notify "changes have finished".
700 * Each call with a 'false' parameter must be matched with a following one
701 * with a 'true' parameter. Unmatched 'true' calls are currently not permitted,
702 * but might be allowed in the future.
704 * GUIs should not complain if they receive extra calls with 'true' as parameter.
705 * They should initiate a redraw of the mark - which may (if necessary) mean
706 * repainting the whole screen if the GUI hasn't tracked the mark's location.
709 notify_mark_change (bool changes_complete
)
711 if (gui
->notify_mark_change
)
712 gui
->notify_mark_change (changes_complete
);
716 /* ---------------------------------------------------------------------------
717 * Convenience for plugins using the old {Hide,Restore}Crosshair API.
718 * This links up to notify the GUI of the expected changes using the new APIs.
720 * Use of this old API is deprecated, as the names don't necessarily reflect
721 * what all GUIs may do in response to the notifications. Keeping these APIs
722 * is aimed at easing transition to the newer API, they will emit a harmless
723 * warning at the time of their first use.
729 static bool warned_old_api
= false;
732 Message (_("WARNING: A plugin is using the deprecated API HideCrosshair().\n"
733 " This API may be removed in a future release of PCB.\n"));
734 warned_old_api
= true;
737 notify_crosshair_change (false);
738 notify_mark_change (false);
742 RestoreCrosshair (void)
744 static bool warned_old_api
= false;
747 Message (_("WARNING: A plugin is using the deprecated API RestoreCrosshair().\n"
748 " This API may be removed in a future release of PCB.\n"));
749 warned_old_api
= true;
752 notify_crosshair_change (true);
753 notify_mark_change (true);
756 /* ---------------------------------------------------------------------------
757 * Returns the square of the given number
766 crosshair_sq_dist (CrosshairType
*crosshair
, Coord x
, Coord y
)
768 return square (x
- crosshair
->X
) + square (y
- crosshair
->Y
);
772 CrosshairType
*crosshair
;
773 double nearest_sq_dist
;
774 bool nearest_is_grid
;
778 /* Snap to a given location if it is the closest thing we found so far.
779 * If "prefer_to_grid" is set, the passed location will take preference
780 * over a closer grid points we already snapped to UNLESS the user is
781 * pressing the SHIFT key. If the SHIFT key is pressed, the closest object
782 * (including grid points), is always preferred.
785 check_snap_object (struct snap_data
*snap_data
, Coord x
, Coord y
,
790 sq_dist
= crosshair_sq_dist (snap_data
->crosshair
, x
, y
);
791 if (sq_dist
<= snap_data
->nearest_sq_dist
||
792 (prefer_to_grid
&& snap_data
->nearest_is_grid
&& !gui
->shift_is_pressed()))
796 snap_data
->nearest_sq_dist
= sq_dist
;
797 snap_data
->nearest_is_grid
= false;
802 check_snap_offgrid_line (struct snap_data
*snap_data
,
803 Coord nearest_grid_x
,
804 Coord nearest_grid_y
)
806 void *ptr1
, *ptr2
, *ptr3
;
813 if (!TEST_FLAG (SNAPPINFLAG
, PCB
))
816 /* Code to snap at some sensible point along a line */
817 /* Pick the nearest grid-point in the x or y direction
818 * to align with, then adjust until we hit the line
820 ans
= SearchObjectByLocation (LINE_TYPE
, &ptr1
, &ptr2
, &ptr3
,
821 Crosshair
.X
, Crosshair
.Y
, PCB
->Grid
/ 2);
827 line
= (LineType
*)ptr2
;
829 /* Allow snapping to off-grid lines when drawing new lines (on
830 * the same layer), and when moving a line end-point
831 * (but don't snap to the same line)
833 if ((Settings
.Mode
!= LINE_MODE
|| CURRENT
!= ptr1
) &&
834 (Settings
.Mode
!= MOVE_MODE
||
835 Crosshair
.AttachedObject
.Ptr1
!= ptr1
||
836 Crosshair
.AttachedObject
.Type
!= LINEPOINT_TYPE
||
837 Crosshair
.AttachedObject
.Ptr2
== line
))
840 dx
= line
->Point2
.X
- line
->Point1
.X
;
841 dy
= line
->Point2
.Y
- line
->Point1
.Y
;
843 /* Try snapping along the X axis */
846 /* Move in the X direction until we hit the line */
847 try_x
= (nearest_grid_y
- line
->Point1
.Y
) / dy
* dx
+ line
->Point1
.X
;
848 try_y
= nearest_grid_y
;
849 check_snap_object (snap_data
, try_x
, try_y
, true);
852 /* Try snapping along the Y axis */
855 try_x
= nearest_grid_x
;
856 try_y
= (nearest_grid_x
- line
->Point1
.X
) / dx
* dy
+ line
->Point1
.Y
;
857 check_snap_object (snap_data
, try_x
, try_y
, true);
860 if (dx
!= dy
) /* If line not parallel with dX = dY direction.. */
862 /* Try snapping diagonally towards the line in the dX = dY direction */
865 dist
= line
->Point1
.Y
- nearest_grid_y
;
867 dist
= ((line
->Point1
.X
- nearest_grid_x
) -
868 (line
->Point1
.Y
- nearest_grid_y
) * dx
/ dy
) / (1 - dx
/ dy
);
870 try_x
= nearest_grid_x
+ dist
;
871 try_y
= nearest_grid_y
+ dist
;
873 check_snap_object (snap_data
, try_x
, try_y
, true);
876 if (dx
!= -dy
) /* If line not parallel with dX = -dY direction.. */
878 /* Try snapping diagonally towards the line in the dX = -dY direction */
881 dist
= nearest_grid_y
- line
->Point1
.Y
;
883 dist
= ((line
->Point1
.X
- nearest_grid_x
) -
884 (line
->Point1
.Y
- nearest_grid_y
) * dx
/ dy
) / (1 + dx
/ dy
);
886 try_x
= nearest_grid_x
+ dist
;
887 try_y
= nearest_grid_y
- dist
;
889 check_snap_object (snap_data
, try_x
, try_y
, true);
893 /* ---------------------------------------------------------------------------
894 * recalculates the passed coordinates to fit the current grid setting
897 FitCrosshairIntoGrid (Coord X
, Coord Y
)
899 Coord nearest_grid_x
, nearest_grid_y
;
900 void *ptr1
, *ptr2
, *ptr3
;
901 struct snap_data snap_data
;
909 Crosshair
.X
= CLAMP (X
, Crosshair
.MinX
, Crosshair
.MaxX
);
910 Crosshair
.Y
= CLAMP (Y
, Crosshair
.MinY
, Crosshair
.MaxY
);
914 nearest_grid_x
= -MIL_TO_COORD (6);
915 nearest_grid_y
= -MIL_TO_COORD (6);
919 nearest_grid_x
= GridFit (Crosshair
.X
, PCB
->Grid
, PCB
->GridOffsetX
);
920 nearest_grid_y
= GridFit (Crosshair
.Y
, PCB
->Grid
, PCB
->GridOffsetY
);
922 if (Marked
.status
&& TEST_FLAG (ORTHOMOVEFLAG
, PCB
))
924 Coord dx
= Crosshair
.X
- Marked
.X
;
925 Coord dy
= Crosshair
.Y
- Marked
.Y
;
926 if (ABS (dx
) > ABS (dy
))
927 nearest_grid_y
= Marked
.Y
;
929 nearest_grid_x
= Marked
.X
;
934 snap_data
.crosshair
= &Crosshair
;
935 snap_data
.nearest_is_grid
= true;
936 snap_data
.x
= nearest_grid_x
;
937 snap_data
.y
= nearest_grid_y
;
939 snap_data
.nearest_sq_dist
= crosshair_sq_dist (&Crosshair
, snap_data
.x
, snap_data
.y
);
941 if (snap_data
.nearest_sq_dist
> PCB
->Grid
/ 3 * PCB
->Grid
/ 3)
948 if (labs (nearest_grid_x
- Crosshair
.X
) > PCB
->Grid
/ 3)
951 if (labs (nearest_grid_y
- Crosshair
.Y
) > PCB
->Grid
/ 3)
954 snap_data
.nearest_sq_dist
= crosshair_sq_dist (&Crosshair
, snap_data
.x
, snap_data
.y
);
958 ans
= SearchObjectByLocation (ELEMENT_TYPE
, &ptr1
, &ptr2
, &ptr3
,
959 Crosshair
.X
, Crosshair
.Y
, PCB
->Grid
/ 2);
961 if (ans
& ELEMENT_TYPE
)
963 ElementType
*el
= (ElementType
*) ptr1
;
964 check_snap_object (&snap_data
, el
->MarkX
, el
->MarkY
, false);
968 if (PCB
->RatDraw
|| TEST_FLAG (SNAPPINFLAG
, PCB
))
969 ans
= SearchObjectByLocation (PAD_TYPE
, &ptr1
, &ptr2
, &ptr3
,
970 Crosshair
.X
, Crosshair
.Y
, 0);
972 /* Avoid self-snapping when moving */
973 if (ans
!= NO_TYPE
&&
974 Settings
.Mode
== MOVE_MODE
&&
975 Crosshair
.AttachedObject
.Type
== ELEMENT_TYPE
&&
976 ptr1
== Crosshair
.AttachedObject
.Ptr1
)
979 if (ans
!= NO_TYPE
&&
980 ( Settings
.Mode
== LINE_MODE
||
981 (Settings
.Mode
== MOVE_MODE
&&
982 Crosshair
.AttachedObject
.Type
== LINEPOINT_TYPE
)))
984 PadType
*pad
= (PadType
*) ptr2
;
985 LayerType
*desired_layer
;
986 Cardinal desired_group
;
987 Cardinal bottom_group
, top_group
;
988 int found_our_layer
= false;
990 desired_layer
= CURRENT
;
991 if (Settings
.Mode
== MOVE_MODE
&&
992 Crosshair
.AttachedObject
.Type
== LINEPOINT_TYPE
)
994 desired_layer
= (LayerType
*)Crosshair
.AttachedObject
.Ptr1
;
997 /* find layer groups of the top and bottom sides */
998 top_group
= GetLayerGroupNumberBySide (TOP_SIDE
);
999 bottom_group
= GetLayerGroupNumberBySide (BOTTOM_SIDE
);
1000 desired_group
= TEST_FLAG (ONSOLDERFLAG
, pad
) ? bottom_group
: top_group
;
1002 GROUP_LOOP (PCB
->Data
, desired_group
);
1004 if (layer
== desired_layer
)
1006 found_our_layer
= true;
1012 if (found_our_layer
== false)
1018 PadType
*pad
= (PadType
*)ptr2
;
1019 check_snap_object (&snap_data
, pad
->Point1
.X
+ (pad
->Point2
.X
- pad
->Point1
.X
) / 2,
1020 pad
->Point1
.Y
+ (pad
->Point2
.Y
- pad
->Point1
.Y
) / 2,
1025 if (PCB
->RatDraw
|| TEST_FLAG (SNAPPINFLAG
, PCB
))
1026 ans
= SearchObjectByLocation (PIN_TYPE
, &ptr1
, &ptr2
, &ptr3
,
1027 Crosshair
.X
, Crosshair
.Y
, 0);
1029 /* Avoid self-snapping when moving */
1030 if (ans
!= NO_TYPE
&&
1031 Settings
.Mode
== MOVE_MODE
&&
1032 Crosshair
.AttachedObject
.Type
== ELEMENT_TYPE
&&
1033 ptr1
== Crosshair
.AttachedObject
.Ptr1
)
1038 PinType
*pin
= (PinType
*)ptr2
;
1039 check_snap_object (&snap_data
, pin
->X
, pin
->Y
, true);
1043 if (TEST_FLAG (SNAPPINFLAG
, PCB
))
1044 ans
= SearchObjectByLocation (VIA_TYPE
, &ptr1
, &ptr2
, &ptr3
,
1045 Crosshair
.X
, Crosshair
.Y
, 0);
1047 /* Avoid snapping vias to any other vias */
1048 if (Settings
.Mode
== MOVE_MODE
&&
1049 Crosshair
.AttachedObject
.Type
== VIA_TYPE
&&
1055 PinType
*pin
= (PinType
*)ptr2
;
1056 check_snap_object (&snap_data
, pin
->X
, pin
->Y
, true);
1060 if (TEST_FLAG (SNAPPINFLAG
, PCB
))
1061 ans
= SearchObjectByLocation (LINEPOINT_TYPE
| ARCPOINT_TYPE
,
1062 &ptr1
, &ptr2
, &ptr3
,
1063 Crosshair
.X
, Crosshair
.Y
, PCB
->Grid
/ 2);
1067 PointType
*pnt
= (PointType
*)ptr3
;
1068 check_snap_object (&snap_data
, pnt
->X
, pnt
->Y
, true);
1071 check_snap_offgrid_line (&snap_data
, nearest_grid_x
, nearest_grid_y
);
1074 if (TEST_FLAG (SNAPPINFLAG
, PCB
))
1075 ans
= SearchObjectByLocation (POLYGONPOINT_TYPE
, &ptr1
, &ptr2
, &ptr3
,
1076 Crosshair
.X
, Crosshair
.Y
, PCB
->Grid
/ 2);
1080 PointType
*pnt
= (PointType
*)ptr3
;
1081 check_snap_object (&snap_data
, pnt
->X
, pnt
->Y
, true);
1084 if (snap_data
.x
>= 0 && snap_data
.y
>= 0)
1086 Crosshair
.X
= snap_data
.x
;
1087 Crosshair
.Y
= snap_data
.y
;
1090 if (Settings
.Mode
== ARROW_MODE
)
1092 ans
= SearchObjectByLocation (LINEPOINT_TYPE
| ARCPOINT_TYPE
,
1093 &ptr1
, &ptr2
, &ptr3
,
1094 Crosshair
.X
, Crosshair
.Y
, PCB
->Grid
/ 2);
1096 hid_action("PointCursor");
1097 else if (!TEST_FLAG(SELECTEDFLAG
, (LineType
*)ptr2
))
1098 hid_actionl("PointCursor","True", NULL
);
1101 if (Settings
.Mode
== LINE_MODE
1102 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
1103 && TEST_FLAG (AUTODRCFLAG
, PCB
))
1106 gui
->set_crosshair (Crosshair
.X
, Crosshair
.Y
, HID_SC_DO_NOTHING
);
1109 /* ---------------------------------------------------------------------------
1110 * move crosshair absolute
1111 * return true if the crosshair was moved from its existing position
1114 MoveCrosshairAbsolute (Coord X
, Coord Y
)
1116 Coord old_x
= Crosshair
.X
;
1117 Coord old_y
= Crosshair
.Y
;
1119 FitCrosshairIntoGrid (X
, Y
);
1121 if (Crosshair
.X
!= old_x
|| Crosshair
.Y
!= old_y
)
1123 Coord new_x
= Crosshair
.X
;
1124 Coord new_y
= Crosshair
.Y
;
1126 /* back up to old position to notify the GUI
1127 * (which might want to erase the old crosshair) */
1128 Crosshair
.X
= old_x
;
1129 Crosshair
.Y
= old_y
;
1130 notify_crosshair_change (false); /* Our caller notifies when it has done */
1132 /* now move forward again */
1133 Crosshair
.X
= new_x
;
1134 Crosshair
.Y
= new_y
;
1140 /* ---------------------------------------------------------------------------
1141 * sets the valid range for the crosshair cursor
1144 SetCrosshairRange (Coord MinX
, Coord MinY
, Coord MaxX
, Coord MaxY
)
1146 Crosshair
.MinX
= MAX (0, MinX
);
1147 Crosshair
.MinY
= MAX (0, MinY
);
1148 Crosshair
.MaxX
= MIN (PCB
->MaxWidth
, MaxX
);
1149 Crosshair
.MaxY
= MIN (PCB
->MaxHeight
, MaxY
);
1151 /* force update of position */
1152 FitCrosshairIntoGrid (Crosshair
.X
, Crosshair
.Y
);
1155 /* ---------------------------------------------------------------------------
1156 * initializes crosshair stuff
1157 * clears the struct, allocates to graphical contexts
1160 InitCrosshair (void)
1162 /* set initial shape */
1163 Crosshair
.shape
= Basic_Crosshair_Shape
;
1165 /* set default limits */
1166 Crosshair
.MinX
= Crosshair
.MinY
= 0;
1167 Crosshair
.MaxX
= PCB
->MaxWidth
;
1168 Crosshair
.MaxY
= PCB
->MaxHeight
;
1170 /* clear the mark */
1171 Marked
.status
= false;
1174 /* ---------------------------------------------------------------------------
1175 * exits crosshair routines, release GCs
1178 DestroyCrosshair (void)
1180 FreePolygonMemory (&Crosshair
.AttachedPolygon
);