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
40 #include "crosshair.h"
50 #ifdef HAVE_LIBDMALLOC
59 /* ---------------------------------------------------------------------------
60 * some local prototypes
62 static void XORPolygon (PolygonType
*, Coord
, Coord
);
63 static void XORDrawElement (ElementType
*, Coord
, Coord
);
64 static void XORDrawBuffer (BufferType
*);
65 static void XORDrawInsertPointObject (void);
66 static void XORDrawMoveOrCopyObject (void);
67 static void XORDrawAttachedLine (Coord
, Coord
, Coord
, Coord
, Coord
);
68 static void XORDrawAttachedArc (Coord
);
71 thindraw_moved_pv (PinType
*pv
, Coord x
, Coord y
)
73 /* Make a copy of the pin structure, moved to the correct position */
74 PinType moved_pv
= *pv
;
78 gui
->thindraw_pcb_pv (Crosshair
.GC
, Crosshair
.GC
, &moved_pv
, true, false);
81 /* ---------------------------------------------------------------------------
82 * creates a tmp polygon with coordinates converted to screen system
85 XORPolygon (PolygonType
*polygon
, Coord dx
, Coord dy
)
88 for (i
= 0; i
< polygon
->PointN
; i
++)
90 Cardinal next
= next_contour_point (polygon
, i
);
91 gui
->draw_line (Crosshair
.GC
,
92 polygon
->Points
[i
].X
+ dx
,
93 polygon
->Points
[i
].Y
+ dy
,
94 polygon
->Points
[next
].X
+ dx
,
95 polygon
->Points
[next
].Y
+ dy
);
99 /*-----------------------------------------------------------
100 * Draws the outline of an arc
103 XORDrawAttachedArc (Coord thick
)
109 Coord wid
= thick
/ 2;
111 wx
= Crosshair
.X
- Crosshair
.AttachedBox
.Point1
.X
;
112 wy
= Crosshair
.Y
- Crosshair
.AttachedBox
.Point1
.Y
;
113 if (wx
== 0 && wy
== 0)
115 arc
.X
= Crosshair
.AttachedBox
.Point1
.X
;
116 arc
.Y
= Crosshair
.AttachedBox
.Point1
.Y
;
117 if (XOR (Crosshair
.AttachedBox
.otherway
, abs (wy
) > abs (wx
)))
119 arc
.X
= Crosshair
.AttachedBox
.Point1
.X
+ abs (wy
) * SGNZ (wx
);
120 sa
= (wx
>= 0) ? 0 : 180;
122 if (abs (wy
) >= 2 * abs (wx
))
123 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 45 : -45;
126 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 90 : -90;
130 arc
.Y
= Crosshair
.AttachedBox
.Point1
.Y
+ abs (wx
) * SGNZ (wy
);
131 sa
= (wy
>= 0) ? -90 : 90;
133 if (abs (wx
) >= 2 * abs (wy
))
134 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -45 : 45;
137 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -90 : 90;
143 arc
.Width
= arc
.Height
= wy
;
144 bx
= GetArcEnds (&arc
);
146 gui
->draw_arc (Crosshair
.GC
, arc
.X
, arc
.Y
, wy
+ wid
, wy
+ wid
, sa
, dir
);
147 if (wid
> pixel_slop
)
149 gui
->draw_arc (Crosshair
.GC
, arc
.X
, arc
.Y
, wy
- wid
, wy
- wid
, sa
, dir
);
150 gui
->draw_arc (Crosshair
.GC
, bx
->X1
, bx
->Y1
,
151 wid
, wid
, sa
, -180 * SGN (dir
));
152 gui
->draw_arc (Crosshair
.GC
, bx
->X2
, bx
->Y2
,
153 wid
, wid
, sa
+ dir
, 180 * SGN (dir
));
157 /*-----------------------------------------------------------
158 * Draws the outline of a line
161 XORDrawAttachedLine (Coord x1
, Coord y1
, Coord x2
, Coord y2
, Coord thick
)
163 Coord dx
, dy
, ox
, oy
;
168 if (dx
!= 0 || dy
!= 0)
169 h
= 0.5 * thick
/ sqrt (SQUARE (dx
) + SQUARE (dy
));
172 ox
= dy
* h
+ 0.5 * SGN (dy
);
173 oy
= -(dx
* h
+ 0.5 * SGN (dx
));
174 gui
->draw_line (Crosshair
.GC
, x1
+ ox
, y1
+ oy
, x2
+ ox
, y2
+ oy
);
175 if (abs (ox
) >= pixel_slop
|| abs (oy
) >= pixel_slop
)
177 Angle angle
= atan2 (dx
, dy
) * 57.295779;
178 gui
->draw_line (Crosshair
.GC
, x1
- ox
, y1
- oy
, x2
- ox
, y2
- oy
);
179 gui
->draw_arc (Crosshair
.GC
,
180 x1
, y1
, thick
/ 2, thick
/ 2, angle
- 180, 180);
181 gui
->draw_arc (Crosshair
.GC
, x2
, y2
, thick
/ 2, thick
/ 2, angle
, 180);
185 /* ---------------------------------------------------------------------------
186 * draws the elements of a loaded circuit which is to be merged in
189 XORDrawElement (ElementType
*Element
, Coord DX
, Coord DY
)
191 /* if no silkscreen, draw the bounding box */
192 if (Element
->ArcN
== 0 && Element
->LineN
== 0)
194 gui
->draw_line (Crosshair
.GC
,
195 DX
+ Element
->BoundingBox
.X1
,
196 DY
+ Element
->BoundingBox
.Y1
,
197 DX
+ Element
->BoundingBox
.X1
,
198 DY
+ Element
->BoundingBox
.Y2
);
199 gui
->draw_line (Crosshair
.GC
,
200 DX
+ Element
->BoundingBox
.X1
,
201 DY
+ Element
->BoundingBox
.Y2
,
202 DX
+ Element
->BoundingBox
.X2
,
203 DY
+ Element
->BoundingBox
.Y2
);
204 gui
->draw_line (Crosshair
.GC
,
205 DX
+ Element
->BoundingBox
.X2
,
206 DY
+ Element
->BoundingBox
.Y2
,
207 DX
+ Element
->BoundingBox
.X2
,
208 DY
+ Element
->BoundingBox
.Y1
);
209 gui
->draw_line (Crosshair
.GC
,
210 DX
+ Element
->BoundingBox
.X2
,
211 DY
+ Element
->BoundingBox
.Y1
,
212 DX
+ Element
->BoundingBox
.X1
,
213 DY
+ Element
->BoundingBox
.Y1
);
217 ELEMENTLINE_LOOP (Element
);
219 gui
->draw_line (Crosshair
.GC
,
222 DX
+ line
->Point2
.X
, DY
+ line
->Point2
.Y
);
226 /* arc coordinates and angles have to be converted to X11 notation */
229 gui
->draw_arc (Crosshair
.GC
,
232 arc
->Width
, arc
->Height
, arc
->StartAngle
, arc
->Delta
);
236 /* pin coordinates and angles have to be converted to X11 notation */
239 thindraw_moved_pv (pin
, DX
, DY
);
246 if (PCB
->InvisibleObjectsOn
||
247 (TEST_FLAG (ONSOLDERFLAG
, pad
) != 0) == Settings
.ShowSolderSide
)
249 /* Make a copy of the pad structure, moved to the correct position */
250 PadType moved_pad
= *pad
;
251 moved_pad
.Point1
.X
+= DX
; moved_pad
.Point1
.Y
+= DY
;
252 moved_pad
.Point2
.X
+= DX
; moved_pad
.Point2
.Y
+= DY
;
254 gui
->thindraw_pcb_pad (Crosshair
.GC
, &moved_pad
, false, false);
259 gui
->draw_line (Crosshair
.GC
,
260 Element
->MarkX
+ DX
- EMARK_SIZE
,
262 Element
->MarkX
+ DX
, Element
->MarkY
+ DY
- EMARK_SIZE
);
263 gui
->draw_line (Crosshair
.GC
,
264 Element
->MarkX
+ DX
+ EMARK_SIZE
,
266 Element
->MarkX
+ DX
, Element
->MarkY
+ DY
- EMARK_SIZE
);
267 gui
->draw_line (Crosshair
.GC
,
268 Element
->MarkX
+ DX
- EMARK_SIZE
,
270 Element
->MarkX
+ DX
, Element
->MarkY
+ DY
+ EMARK_SIZE
);
271 gui
->draw_line (Crosshair
.GC
,
272 Element
->MarkX
+ DX
+ EMARK_SIZE
,
274 Element
->MarkX
+ DX
, Element
->MarkY
+ DY
+ EMARK_SIZE
);
277 /* ---------------------------------------------------------------------------
278 * draws all visible and attached objects of the pastebuffer
281 XORDrawBuffer (BufferType
*Buffer
)
287 x
= Crosshair
.X
- Buffer
->X
;
288 y
= Crosshair
.Y
- Buffer
->Y
;
290 /* draw all visible layers */
291 for (i
= 0; i
< max_copper_layer
+ 2; i
++)
292 if (PCB
->Data
->Layer
[i
].On
)
294 LayerType
*layer
= &Buffer
->Data
->Layer
[i
];
299 XORDrawAttachedLine(x +line->Point1.X,
300 y +line->Point1.Y, x +line->Point2.X,
301 y +line->Point2.Y, line->Thickness);
303 gui
->draw_line (Crosshair
.GC
,
304 x
+ line
->Point1
.X
, y
+ line
->Point1
.Y
,
305 x
+ line
->Point2
.X
, y
+ line
->Point2
.Y
);
310 gui
->draw_arc (Crosshair
.GC
,
314 arc
->Height
, arc
->StartAngle
, arc
->Delta
);
319 BoxType
*box
= &text
->BoundingBox
;
320 gui
->draw_rect (Crosshair
.GC
,
321 x
+ box
->X1
, y
+ box
->Y1
, x
+ box
->X2
, y
+ box
->Y2
);
324 /* the tmp polygon has n+1 points because the first
325 * and the last one are set to the same coordinates
327 POLYGON_LOOP (layer
);
329 XORPolygon (polygon
, x
, y
);
334 /* draw elements if visible */
335 if (PCB
->PinOn
&& PCB
->ElementOn
)
336 ELEMENT_LOOP (Buffer
->Data
);
338 if (FRONT (element
) || PCB
->InvisibleObjectsOn
)
339 XORDrawElement (element
, x
, y
);
345 VIA_LOOP (Buffer
->Data
);
347 thindraw_moved_pv (via
, x
, y
);
352 /* ---------------------------------------------------------------------------
353 * draws the rubberband to insert points into polygons/lines/...
356 XORDrawInsertPointObject (void)
358 LineType
*line
= (LineType
*) Crosshair
.AttachedObject
.Ptr2
;
359 PointType
*point
= (PointType
*) Crosshair
.AttachedObject
.Ptr3
;
361 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
363 gui
->draw_line (Crosshair
.GC
,
364 point
->X
, point
->Y
, line
->Point1
.X
, line
->Point1
.Y
);
365 gui
->draw_line (Crosshair
.GC
,
366 point
->X
, point
->Y
, line
->Point2
.X
, line
->Point2
.Y
);
370 /* ---------------------------------------------------------------------------
371 * draws the attached object while in MOVE_MODE or COPY_MODE
374 XORDrawMoveOrCopyObject (void)
378 Coord dx
= Crosshair
.X
- Crosshair
.AttachedObject
.X
,
379 dy
= Crosshair
.Y
- Crosshair
.AttachedObject
.Y
;
381 switch (Crosshair
.AttachedObject
.Type
)
385 PinType
*via
= (PinType
*) Crosshair
.AttachedObject
.Ptr1
;
386 thindraw_moved_pv (via
, dx
, dy
);
392 LineType
*line
= (LineType
*) Crosshair
.AttachedObject
.Ptr2
;
394 XORDrawAttachedLine (line
->Point1
.X
+ dx
, line
->Point1
.Y
+ dy
,
395 line
->Point2
.X
+ dx
, line
->Point2
.Y
+ dy
,
402 ArcType
*Arc
= (ArcType
*) Crosshair
.AttachedObject
.Ptr2
;
404 gui
->draw_arc (Crosshair
.GC
,
407 Arc
->Width
, Arc
->Height
, Arc
->StartAngle
, Arc
->Delta
);
413 PolygonType
*polygon
=
414 (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
;
416 /* the tmp polygon has n+1 points because the first
417 * and the last one are set to the same coordinates
419 XORPolygon (polygon
, dx
, dy
);
428 line
= (LineType
*) Crosshair
.AttachedObject
.Ptr2
;
429 point
= (PointType
*) Crosshair
.AttachedObject
.Ptr3
;
430 if (point
== &line
->Point1
)
431 XORDrawAttachedLine (point
->X
+ dx
,
432 point
->Y
+ dy
, line
->Point2
.X
,
433 line
->Point2
.Y
, line
->Thickness
);
435 XORDrawAttachedLine (point
->X
+ dx
,
436 point
->Y
+ dy
, line
->Point1
.X
,
437 line
->Point1
.Y
, line
->Thickness
);
441 case POLYGONPOINT_TYPE
:
443 PolygonType
*polygon
;
445 Cardinal point_idx
, prev
, next
;
447 polygon
= (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
;
448 point
= (PointType
*) Crosshair
.AttachedObject
.Ptr3
;
449 point_idx
= polygon_point_idx (polygon
, point
);
451 /* get previous and following point */
452 prev
= prev_contour_point (polygon
, point_idx
);
453 next
= next_contour_point (polygon
, point_idx
);
455 /* draw the two segments */
456 gui
->draw_line (Crosshair
.GC
,
457 polygon
->Points
[prev
].X
, polygon
->Points
[prev
].Y
,
458 point
->X
+ dx
, point
->Y
+ dy
);
459 gui
->draw_line (Crosshair
.GC
,
460 point
->X
+ dx
, point
->Y
+ dy
,
461 polygon
->Points
[next
].X
, polygon
->Points
[next
].Y
);
465 case ELEMENTNAME_TYPE
:
467 /* locate the element "mark" and draw an association line from crosshair to it */
468 ElementType
*element
=
469 (ElementType
*) Crosshair
.AttachedObject
.Ptr1
;
471 gui
->draw_line (Crosshair
.GC
,
473 element
->MarkY
, Crosshair
.X
, Crosshair
.Y
);
474 /* fall through to move the text as a box outline */
478 TextType
*text
= (TextType
*) Crosshair
.AttachedObject
.Ptr2
;
479 BoxType
*box
= &text
->BoundingBox
;
480 gui
->draw_rect (Crosshair
.GC
,
482 box
->Y1
+ dy
, box
->X2
+ dx
, box
->Y2
+ dy
);
486 /* pin/pad movements result in moving an element */
490 XORDrawElement ((ElementType
*) Crosshair
.AttachedObject
.Ptr2
, dx
, dy
);
494 /* draw the attached rubberband lines too */
495 i
= Crosshair
.AttachedObject
.RubberbandN
;
496 ptr
= Crosshair
.AttachedObject
.Rubberband
;
499 PointType
*point1
, *point2
;
501 if (TEST_FLAG (VIAFLAG
, ptr
->Line
))
503 /* this is a rat going to a polygon. do not draw for rubberband */;
505 else if (TEST_FLAG (RUBBERENDFLAG
, ptr
->Line
))
507 /* 'point1' is always the fix-point */
508 if (ptr
->MovedPoint
== &ptr
->Line
->Point1
)
510 point1
= &ptr
->Line
->Point2
;
511 point2
= &ptr
->Line
->Point1
;
515 point1
= &ptr
->Line
->Point1
;
516 point2
= &ptr
->Line
->Point2
;
518 XORDrawAttachedLine (point1
->X
,
519 point1
->Y
, point2
->X
+ dx
,
520 point2
->Y
+ dy
, ptr
->Line
->Thickness
);
522 else if (ptr
->MovedPoint
== &ptr
->Line
->Point1
)
523 XORDrawAttachedLine (ptr
->Line
->Point1
.X
+ dx
,
524 ptr
->Line
->Point1
.Y
+ dy
,
525 ptr
->Line
->Point2
.X
+ dx
,
526 ptr
->Line
->Point2
.Y
+ dy
, ptr
->Line
->Thickness
);
533 /* ---------------------------------------------------------------------------
534 * draws additional stuff that follows the crosshair
539 switch (Settings
.Mode
)
543 /* Make a dummy via structure to draw from */
547 via
.Thickness
= Settings
.ViaThickness
;
548 via
.Clearance
= 2 * Settings
.Keepaway
;
549 via
.DrillingHole
= Settings
.ViaDrillingHole
;
551 via
.Flags
= NoFlags ();
553 gui
->thindraw_pcb_pv (Crosshair
.GC
, Crosshair
.GC
, &via
, true, false);
555 if (TEST_FLAG (SHOWDRCFLAG
, PCB
))
557 /* XXX: Naughty cheat - use the mask to draw DRC clearance! */
558 via
.Mask
= Settings
.ViaThickness
+ PCB
->Bloat
* 2;
559 gui
->set_color (Crosshair
.GC
, Settings
.CrossColor
);
560 gui
->thindraw_pcb_pv (Crosshair
.GC
, Crosshair
.GC
, &via
, false, true);
561 gui
->set_color (Crosshair
.GC
, Settings
.CrosshairColor
);
566 /* the attached line is used by both LINEMODE, POLYGON_MODE and POLYGONHOLE_MODE*/
568 case POLYGONHOLE_MODE
:
569 /* draw only if starting point is set */
570 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
571 gui
->draw_line (Crosshair
.GC
,
572 Crosshair
.AttachedLine
.Point1
.X
,
573 Crosshair
.AttachedLine
.Point1
.Y
,
574 Crosshair
.AttachedLine
.Point2
.X
,
575 Crosshair
.AttachedLine
.Point2
.Y
);
577 /* draw attached polygon only if in POLYGON_MODE or POLYGONHOLE_MODE */
578 if (Crosshair
.AttachedPolygon
.PointN
> 1)
580 XORPolygon (&Crosshair
.AttachedPolygon
, 0, 0);
585 if (Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
587 XORDrawAttachedArc (Settings
.LineThickness
);
588 if (TEST_FLAG (SHOWDRCFLAG
, PCB
))
590 gui
->set_color (Crosshair
.GC
, Settings
.CrossColor
);
591 XORDrawAttachedArc (Settings
.LineThickness
+
592 2 * (PCB
->Bloat
+ 1));
593 gui
->set_color (Crosshair
.GC
, Settings
.CrosshairColor
);
600 /* draw only if starting point exists and the line has length */
601 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
&&
602 Crosshair
.AttachedLine
.draw
)
604 XORDrawAttachedLine (Crosshair
.AttachedLine
.Point1
.X
,
605 Crosshair
.AttachedLine
.Point1
.Y
,
606 Crosshair
.AttachedLine
.Point2
.X
,
607 Crosshair
.AttachedLine
.Point2
.Y
,
608 PCB
->RatDraw
? 10 : Settings
.LineThickness
);
609 /* draw two lines ? */
611 XORDrawAttachedLine (Crosshair
.AttachedLine
.Point2
.X
,
612 Crosshair
.AttachedLine
.Point2
.Y
,
613 Crosshair
.X
, Crosshair
.Y
,
614 PCB
->RatDraw
? 10 : Settings
.LineThickness
);
615 if (TEST_FLAG (SHOWDRCFLAG
, PCB
))
617 gui
->set_color (Crosshair
.GC
, Settings
.CrossColor
);
618 XORDrawAttachedLine (Crosshair
.AttachedLine
.Point1
.X
,
619 Crosshair
.AttachedLine
.Point1
.Y
,
620 Crosshair
.AttachedLine
.Point2
.X
,
621 Crosshair
.AttachedLine
.Point2
.Y
,
622 PCB
->RatDraw
? 10 : Settings
.LineThickness
623 + 2 * (PCB
->Bloat
+ 1));
625 XORDrawAttachedLine (Crosshair
.AttachedLine
.Point2
.X
,
626 Crosshair
.AttachedLine
.Point2
.Y
,
627 Crosshair
.X
, Crosshair
.Y
,
628 PCB
->RatDraw
? 10 : Settings
.
629 LineThickness
+ 2 * (PCB
->Bloat
+ 1));
630 gui
->set_color (Crosshair
.GC
, Settings
.CrosshairColor
);
635 case PASTEBUFFER_MODE
:
636 XORDrawBuffer (PASTEBUFFER
);
641 XORDrawMoveOrCopyObject ();
644 case INSERTPOINT_MODE
:
645 XORDrawInsertPointObject ();
649 /* an attached box does not depend on a special mode */
650 if (Crosshair
.AttachedBox
.State
== STATE_SECOND
||
651 Crosshair
.AttachedBox
.State
== STATE_THIRD
)
653 Coord x1
, y1
, x2
, y2
;
655 x1
= Crosshair
.AttachedBox
.Point1
.X
;
656 y1
= Crosshair
.AttachedBox
.Point1
.Y
;
657 x2
= Crosshair
.AttachedBox
.Point2
.X
;
658 y2
= Crosshair
.AttachedBox
.Point2
.Y
;
659 gui
->draw_rect (Crosshair
.GC
, x1
, y1
, x2
, y2
);
664 /* --------------------------------------------------------------------------
665 * draw the marker position
670 /* Mark is not drawn when it is not set */
674 gui
->draw_line (Crosshair
.GC
,
675 Marked
.X
- MARK_SIZE
,
676 Marked
.Y
- MARK_SIZE
,
677 Marked
.X
+ MARK_SIZE
, Marked
.Y
+ MARK_SIZE
);
678 gui
->draw_line (Crosshair
.GC
,
679 Marked
.X
+ MARK_SIZE
,
680 Marked
.Y
- MARK_SIZE
,
681 Marked
.X
- MARK_SIZE
, Marked
.Y
+ MARK_SIZE
);
684 /* ---------------------------------------------------------------------------
685 * Returns the nearest grid-point to the given Coord
688 GridFit (Coord x
, Coord grid_spacing
, Coord grid_offset
)
691 x
= grid_spacing
* round ((double) x
/ grid_spacing
);
697 /* ---------------------------------------------------------------------------
698 * notify the GUI that data relating to the crosshair is being changed.
700 * The argument passed is false to notify "changes are about to happen",
701 * and true to notify "changes have finished".
703 * Each call with a 'false' parameter must be matched with a following one
704 * with a 'true' parameter. Unmatched 'true' calls are currently not permitted,
705 * but might be allowed in the future.
707 * GUIs should not complain if they receive extra calls with 'true' as parameter.
708 * They should initiate a redraw of the crosshair attached objects - which may
709 * (if necessary) mean repainting the whole screen if the GUI hasn't tracked the
710 * location of existing attached drawing.
713 notify_crosshair_change (bool changes_complete
)
715 if (gui
->notify_crosshair_change
)
716 gui
->notify_crosshair_change (changes_complete
);
720 /* ---------------------------------------------------------------------------
721 * notify the GUI that data relating to the mark is being changed.
723 * The argument passed is false to notify "changes are about to happen",
724 * and true to notify "changes have finished".
726 * Each call with a 'false' parameter must be matched with a following one
727 * with a 'true' parameter. Unmatched 'true' calls are currently not permitted,
728 * but might be allowed in the future.
730 * GUIs should not complain if they receive extra calls with 'true' as parameter.
731 * They should initiate a redraw of the mark - which may (if necessary) mean
732 * repainting the whole screen if the GUI hasn't tracked the mark's location.
735 notify_mark_change (bool changes_complete
)
737 if (gui
->notify_mark_change
)
738 gui
->notify_mark_change (changes_complete
);
742 /* ---------------------------------------------------------------------------
743 * Convenience for plugins using the old {Hide,Restore}Crosshair API.
744 * This links up to notify the GUI of the expected changes using the new APIs.
746 * Use of this old API is deprecated, as the names don't necessarily reflect
747 * what all GUIs may do in response to the notifications. Keeping these APIs
748 * is aimed at easing transition to the newer API, they will emit a harmless
749 * warning at the time of their first use.
755 static bool warned_old_api
= false;
758 Message (_("WARNING: A plugin is using the deprecated API HideCrosshair().\n"
759 " This API may be removed in a future release of PCB.\n"));
760 warned_old_api
= true;
763 notify_crosshair_change (false);
764 notify_mark_change (false);
768 RestoreCrosshair (void)
770 static bool warned_old_api
= false;
773 Message (_("WARNING: A plugin is using the deprecated API RestoreCrosshair().\n"
774 " This API may be removed in a future release of PCB.\n"));
775 warned_old_api
= true;
778 notify_crosshair_change (true);
779 notify_mark_change (true);
782 /* ---------------------------------------------------------------------------
783 * Returns the square of the given number
792 crosshair_sq_dist (CrosshairType
*crosshair
, Coord x
, Coord y
)
794 return square (x
- crosshair
->X
) + square (y
- crosshair
->Y
);
798 CrosshairType
*crosshair
;
799 double nearest_sq_dist
;
800 bool nearest_is_grid
;
804 /* Snap to a given location if it is the closest thing we found so far.
805 * If "prefer_to_grid" is set, the passed location will take preference
806 * over a closer grid points we already snapped to UNLESS the user is
807 * pressing the SHIFT key. If the SHIFT key is pressed, the closest object
808 * (including grid points), is always preferred.
811 check_snap_object (struct snap_data
*snap_data
, Coord x
, Coord y
,
816 sq_dist
= crosshair_sq_dist (snap_data
->crosshair
, x
, y
);
817 if (sq_dist
<= snap_data
->nearest_sq_dist
||
818 (prefer_to_grid
&& snap_data
->nearest_is_grid
&& !gui
->shift_is_pressed()))
822 snap_data
->nearest_sq_dist
= sq_dist
;
823 snap_data
->nearest_is_grid
= false;
828 check_snap_offgrid_line (struct snap_data
*snap_data
,
829 Coord nearest_grid_x
,
830 Coord nearest_grid_y
)
832 void *ptr1
, *ptr2
, *ptr3
;
839 if (!TEST_FLAG (SNAPPINFLAG
, PCB
))
842 /* Code to snap at some sensible point along a line */
843 /* Pick the nearest grid-point in the x or y direction
844 * to align with, then adjust until we hit the line
846 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
847 LINE_TYPE
, &ptr1
, &ptr2
, &ptr3
);
852 line
= (LineType
*)ptr2
;
854 /* Allow snapping to off-grid lines when drawing new lines (on
855 * the same layer), and when moving a line end-point
856 * (but don't snap to the same line)
858 if ((Settings
.Mode
!= LINE_MODE
|| CURRENT
!= ptr1
) &&
859 (Settings
.Mode
!= MOVE_MODE
||
860 Crosshair
.AttachedObject
.Ptr1
!= ptr1
||
861 Crosshair
.AttachedObject
.Type
!= LINEPOINT_TYPE
||
862 Crosshair
.AttachedObject
.Ptr2
== line
))
865 dx
= line
->Point2
.X
- line
->Point1
.X
;
866 dy
= line
->Point2
.Y
- line
->Point1
.Y
;
868 /* Try snapping along the X axis */
871 /* Move in the X direction until we hit the line */
872 try_x
= (nearest_grid_y
- line
->Point1
.Y
) / dy
* dx
+ line
->Point1
.X
;
873 try_y
= nearest_grid_y
;
874 check_snap_object (snap_data
, try_x
, try_y
, true);
877 /* Try snapping along the Y axis */
880 try_x
= nearest_grid_x
;
881 try_y
= (nearest_grid_x
- line
->Point1
.X
) / dx
* dy
+ line
->Point1
.Y
;
882 check_snap_object (snap_data
, try_x
, try_y
, true);
885 if (dx
!= dy
) /* If line not parallel with dX = dY direction.. */
887 /* Try snapping diagonally towards the line in the dX = dY direction */
890 dist
= line
->Point1
.Y
- nearest_grid_y
;
892 dist
= ((line
->Point1
.X
- nearest_grid_x
) -
893 (line
->Point1
.Y
- nearest_grid_y
) * dx
/ dy
) / (1 - dx
/ dy
);
895 try_x
= nearest_grid_x
+ dist
;
896 try_y
= nearest_grid_y
+ dist
;
898 check_snap_object (snap_data
, try_x
, try_y
, true);
901 if (dx
!= -dy
) /* If line not parallel with dX = -dY direction.. */
903 /* Try snapping diagonally towards the line in the dX = -dY direction */
906 dist
= nearest_grid_y
- line
->Point1
.Y
;
908 dist
= ((line
->Point1
.X
- nearest_grid_x
) -
909 (line
->Point1
.Y
- nearest_grid_y
) * dx
/ dy
) / (1 + dx
/ dy
);
911 try_x
= nearest_grid_x
+ dist
;
912 try_y
= nearest_grid_y
- dist
;
914 check_snap_object (snap_data
, try_x
, try_y
, true);
918 /* ---------------------------------------------------------------------------
919 * recalculates the passed coordinates to fit the current grid setting
922 FitCrosshairIntoGrid (Coord X
, Coord Y
)
924 Coord nearest_grid_x
, nearest_grid_y
;
925 void *ptr1
, *ptr2
, *ptr3
;
926 struct snap_data snap_data
;
929 Crosshair
.X
= CLAMP (X
, Crosshair
.MinX
, Crosshair
.MaxX
);
930 Crosshair
.Y
= CLAMP (Y
, Crosshair
.MinY
, Crosshair
.MaxY
);
934 nearest_grid_x
= -MIL_TO_COORD (6);
935 nearest_grid_y
= -MIL_TO_COORD (6);
939 nearest_grid_x
= GridFit (Crosshair
.X
, PCB
->Grid
, PCB
->GridOffsetX
);
940 nearest_grid_y
= GridFit (Crosshair
.Y
, PCB
->Grid
, PCB
->GridOffsetY
);
942 if (Marked
.status
&& TEST_FLAG (ORTHOMOVEFLAG
, PCB
))
944 Coord dx
= Crosshair
.X
- Marked
.X
;
945 Coord dy
= Crosshair
.Y
- Marked
.Y
;
946 if (ABS (dx
) > ABS (dy
))
947 nearest_grid_y
= Marked
.Y
;
949 nearest_grid_x
= Marked
.X
;
954 snap_data
.crosshair
= &Crosshair
;
955 snap_data
.nearest_sq_dist
=
956 crosshair_sq_dist (&Crosshair
, nearest_grid_x
, nearest_grid_y
);
957 snap_data
.nearest_is_grid
= true;
958 snap_data
.x
= nearest_grid_x
;
959 snap_data
.y
= nearest_grid_y
;
963 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
964 ELEMENT_TYPE
, &ptr1
, &ptr2
, &ptr3
);
966 if (ans
& ELEMENT_TYPE
)
968 ElementType
*el
= (ElementType
*) ptr1
;
969 check_snap_object (&snap_data
, el
->MarkX
, el
->MarkY
, false);
973 if (PCB
->RatDraw
|| TEST_FLAG (SNAPPINFLAG
, PCB
))
974 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
975 PAD_TYPE
, &ptr1
, &ptr2
, &ptr3
);
977 /* Avoid self-snapping when moving */
978 if (ans
!= NO_TYPE
&&
979 Settings
.Mode
== MOVE_MODE
&&
980 Crosshair
.AttachedObject
.Type
== ELEMENT_TYPE
&&
981 ptr1
== Crosshair
.AttachedObject
.Ptr1
)
984 if (ans
!= NO_TYPE
&&
985 ( Settings
.Mode
== LINE_MODE
||
986 (Settings
.Mode
== MOVE_MODE
&&
987 Crosshair
.AttachedObject
.Type
== LINEPOINT_TYPE
)))
989 PadType
*pad
= (PadType
*) ptr2
;
990 LayerType
*desired_layer
;
991 Cardinal desired_group
;
992 Cardinal SLayer
, CLayer
;
993 int found_our_layer
= false;
995 desired_layer
= CURRENT
;
996 if (Settings
.Mode
== MOVE_MODE
&&
997 Crosshair
.AttachedObject
.Type
== LINEPOINT_TYPE
)
999 desired_layer
= (LayerType
*)Crosshair
.AttachedObject
.Ptr1
;
1002 /* find layer groups of the component side and solder side */
1003 SLayer
= GetLayerGroupNumberByNumber (solder_silk_layer
);
1004 CLayer
= GetLayerGroupNumberByNumber (component_silk_layer
);
1005 desired_group
= TEST_FLAG (ONSOLDERFLAG
, pad
) ? SLayer
: CLayer
;
1007 GROUP_LOOP (PCB
->Data
, desired_group
);
1009 if (layer
== desired_layer
)
1011 found_our_layer
= true;
1017 if (found_our_layer
== false)
1023 PadType
*pad
= (PadType
*)ptr2
;
1024 check_snap_object (&snap_data
, pad
->Point1
.X
+ (pad
->Point2
.X
- pad
->Point1
.X
) / 2,
1025 pad
->Point1
.Y
+ (pad
->Point2
.Y
- pad
->Point1
.Y
) / 2,
1030 if (PCB
->RatDraw
|| TEST_FLAG (SNAPPINFLAG
, PCB
))
1031 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
1032 PIN_TYPE
, &ptr1
, &ptr2
, &ptr3
);
1034 /* Avoid self-snapping when moving */
1035 if (ans
!= NO_TYPE
&&
1036 Settings
.Mode
== MOVE_MODE
&&
1037 Crosshair
.AttachedObject
.Type
== ELEMENT_TYPE
&&
1038 ptr1
== Crosshair
.AttachedObject
.Ptr1
)
1043 PinType
*pin
= (PinType
*)ptr2
;
1044 check_snap_object (&snap_data
, pin
->X
, pin
->Y
, true);
1048 if (TEST_FLAG (SNAPPINFLAG
, PCB
))
1049 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
1050 VIA_TYPE
, &ptr1
, &ptr2
, &ptr3
);
1052 /* Avoid snapping vias to any other vias */
1053 if (Settings
.Mode
== MOVE_MODE
&&
1054 Crosshair
.AttachedObject
.Type
== VIA_TYPE
&&
1060 PinType
*pin
= (PinType
*)ptr2
;
1061 check_snap_object (&snap_data
, pin
->X
, pin
->Y
, true);
1065 if (TEST_FLAG (SNAPPINFLAG
, PCB
))
1066 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
1067 LINEPOINT_TYPE
| ARCPOINT_TYPE
,
1068 &ptr1
, &ptr2
, &ptr3
);
1072 PointType
*pnt
= (PointType
*)ptr3
;
1073 check_snap_object (&snap_data
, pnt
->X
, pnt
->Y
, true);
1076 check_snap_offgrid_line (&snap_data
, nearest_grid_x
, nearest_grid_y
);
1079 if (TEST_FLAG (SNAPPINFLAG
, PCB
))
1080 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
1081 POLYGONPOINT_TYPE
, &ptr1
, &ptr2
, &ptr3
);
1085 PointType
*pnt
= (PointType
*)ptr3
;
1086 check_snap_object (&snap_data
, pnt
->X
, pnt
->Y
, true);
1089 if (snap_data
.x
>= 0 && snap_data
.y
>= 0)
1091 Crosshair
.X
= snap_data
.x
;
1092 Crosshair
.Y
= snap_data
.y
;
1095 if (Settings
.Mode
== ARROW_MODE
)
1097 ans
= SearchScreenGridSlop (Crosshair
.X
, Crosshair
.Y
,
1098 LINEPOINT_TYPE
| ARCPOINT_TYPE
,
1099 &ptr1
, &ptr2
, &ptr3
);
1101 hid_action("PointCursor");
1102 else if (!TEST_FLAG(SELECTEDFLAG
, (LineType
*)ptr2
))
1103 hid_actionl("PointCursor","True", NULL
);
1106 if (Settings
.Mode
== LINE_MODE
1107 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
1108 && TEST_FLAG (AUTODRCFLAG
, PCB
))
1111 gui
->set_crosshair (Crosshair
.X
, Crosshair
.Y
, HID_SC_DO_NOTHING
);
1114 /* ---------------------------------------------------------------------------
1115 * move crosshair relative (has to be switched off)
1118 MoveCrosshairRelative (Coord DeltaX
, Coord DeltaY
)
1120 FitCrosshairIntoGrid (Crosshair
.X
+ DeltaX
, Crosshair
.Y
+ DeltaY
);
1123 /* ---------------------------------------------------------------------------
1124 * move crosshair absolute
1125 * return true if the crosshair was moved from its existing position
1128 MoveCrosshairAbsolute (Coord X
, Coord Y
)
1133 FitCrosshairIntoGrid (X
, Y
);
1134 if (Crosshair
.X
!= x
|| Crosshair
.Y
!= y
)
1136 /* back up to old position to notify the GUI
1137 * (which might want to erase the old crosshair) */
1143 notify_crosshair_change (false); /* Our caller notifies when it has done */
1144 /* now move forward again */
1152 /* ---------------------------------------------------------------------------
1153 * sets the valid range for the crosshair cursor
1156 SetCrosshairRange (Coord MinX
, Coord MinY
, Coord MaxX
, Coord MaxY
)
1158 Crosshair
.MinX
= MAX (0, MinX
);
1159 Crosshair
.MinY
= MAX (0, MinY
);
1160 Crosshair
.MaxX
= MIN (PCB
->MaxWidth
, MaxX
);
1161 Crosshair
.MaxY
= MIN (PCB
->MaxHeight
, MaxY
);
1163 /* force update of position */
1164 MoveCrosshairRelative (0, 0);
1167 /* ---------------------------------------------------------------------------
1168 * initializes crosshair stuff
1169 * clears the struct, allocates to graphical contexts
1172 InitCrosshair (void)
1174 Crosshair
.GC
= gui
->make_gc ();
1176 gui
->set_color (Crosshair
.GC
, Settings
.CrosshairColor
);
1177 gui
->set_draw_xor (Crosshair
.GC
, 1);
1178 gui
->set_line_cap (Crosshair
.GC
, Trace_Cap
);
1179 gui
->set_line_width (Crosshair
.GC
, 1);
1181 /* set initial shape */
1182 Crosshair
.shape
= Basic_Crosshair_Shape
;
1184 /* set default limits */
1185 Crosshair
.MinX
= Crosshair
.MinY
= 0;
1186 Crosshair
.MaxX
= PCB
->MaxWidth
;
1187 Crosshair
.MaxY
= PCB
->MaxHeight
;
1189 /* clear the mark */
1190 Marked
.status
= false;
1193 /* ---------------------------------------------------------------------------
1194 * exits crosshair routines, release GCs
1197 DestroyCrosshair (void)
1199 FreePolygonMemory (&Crosshair
.AttachedPolygon
);
1200 gui
->destroy_gc (Crosshair
.GC
);