1 /* 15 Oct 2008 Ineiev: add CycleCrosshair action */
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 Thomas Nau
8 * Copyright (C) 1997, 1998, 1999, 2000, 2001 Harry Eaton
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 * Harry Eaton, 6697 Buttonhole Ct, Columbia, MD 21044, USA
26 * haceaton@aplcomm.jhuapl.edu
30 /* action routines for output window
40 #include "autoplace.h"
41 #include "autoroute.h"
47 #include "crosshair.h"
61 /*#include "print.h"*/
66 #include "rubberband.h"
74 #include "pcb-printf.h"
77 #include <stdlib.h> /* rand() */
79 #ifdef HAVE_LIBDMALLOC
83 /* for fork() and friends */
88 #ifdef HAVE_SYS_WAIT_H
92 /* ---------------------------------------------------------------------------
122 F_ElementConnections
,
163 F_ResetLinesAndPolygons
,
164 F_ResetPinsViasAndPads
,
185 F_ToggleAllDirections
,
196 F_ToggleRubberBandMode
,
197 F_ToggleStartDirection
,
202 F_ToggleThindrawPoly
,
216 typedef struct /* used to identify subfunctions */
221 FunctionType
, *FunctionTypePtr
;
223 /* --------------------------------------------------------------------------- */
225 /* %start-doc actions 00delta
227 Many actions take a @code{delta} parameter as the last parameter,
228 which is an amount to change something. That @code{delta} may include
229 units, as an additional parameter, such as @code{Action(Object,5,mm)}.
230 If no units are specified, the default is PCB's native units
231 (currently 1/100 mil). Also, if the delta is prefixed by @code{+} or
232 @code{-}, the size is increased or decreased by that amount.
233 Otherwise, the size size is set to the given amount.
237 Action(Object,+0.5,mm)
241 Actions which take a @code{delta} parameter which do not accept all
242 these options will specify what they do take.
246 /* %start-doc actions 00objects
248 Many actions act on indicated objects on the board. They will have
249 parameters like @code{ToggleObject} or @code{SelectedVias} to indicate
250 what group of objects they act on. Unless otherwise specified, these
251 parameters are defined as follows:
257 Affects the object under the mouse pointer. If this action is invoked
258 from a menu or script, the user will be prompted to click on an
259 object, which is then the object affected.
262 @itemx SelectedObjects
264 Affects all objects which are currently selected. At least, all
265 selected objects for which the given action makes sense.
269 @itemx Selected@var{Type}
271 Affects all objects which are both selected and of the @var{Type} specified.
277 /* %start-doc actions 00macros
281 Pins, pads, and vias can have various shapes. All may be round. Pins
282 and pads may be square (obviously "square" pads are usually
283 rectangular). Pins and vias may be octagonal. When you change a
284 shape flag of an element, you actually change all of its pins and
287 Note that the square flag takes precedence over the octagon flag,
288 thus, if both the square and octagon flags are set, the object is
289 square. When the square flag is cleared, the pins and pads will be
290 either round or, if the octagon flag is set, octagonal.
296 /* ---------------------------------------------------------------------------
297 * some local identifiers
299 static PointType InsertedPoint
;
300 static LayerTypePtr lastLayer
;
313 bool Moving
; /* selected type clicked on */
314 int Hit
; /* move type clicked on */
321 static int defer_updates
= 0;
322 static int defer_needs_update
= 0;
324 static Cardinal polyIndex
= 0;
325 static bool saved_mode
= false;
326 #ifdef HAVE_LIBSTROKE
327 static bool mid_stroke
= false;
328 static BoxType StrokeBox
;
330 static FunctionType Functions
[] = {
331 {"AddSelected", F_AddSelected
},
333 {"AllConnections", F_AllConnections
},
334 {"AllRats", F_AllRats
},
335 {"AllUnusedPins", F_AllUnusedPins
},
339 {"Description", F_Description
},
340 {"Cancel", F_Cancel
},
341 {"Center", F_Center
},
343 {"ClearAndRedraw", F_ClearAndRedraw
},
344 {"ClearList", F_ClearList
},
346 {"Connection", F_Connection
},
347 {"Convert", F_Convert
},
349 {"CycleClip", F_CycleClip
},
350 {"CycleCrosshair", F_CycleCrosshair
},
351 {"DeleteRats", F_DeleteRats
},
353 {"DrillReport", F_DrillReport
},
354 {"Element", F_Element
},
355 {"ElementByName", F_ElementByName
},
356 {"ElementConnections", F_ElementConnections
},
357 {"ElementToBuffer", F_ElementToBuffer
},
358 {"Escape", F_Escape
},
360 {"FlipElement", F_FlipElement
},
361 {"FoundPins", F_FoundPins
},
363 {"InsertPoint", F_InsertPoint
},
365 {"Layout", F_Layout
},
366 {"LayoutAs", F_LayoutAs
},
367 {"LayoutToBuffer", F_LayoutToBuffer
},
369 {"LineSize", F_LineSize
},
371 {"Mirror", F_Mirror
},
373 {"NameOnPCB", F_NameOnPCB
},
374 {"Netlist", F_Netlist
},
375 {"NetByName", F_NetByName
},
377 {"Notify", F_Notify
},
378 {"Object", F_Object
},
379 {"ObjectByName", F_ObjectByName
},
380 {"PasteBuffer", F_PasteBuffer
},
381 {"PadByName", F_PadByName
},
382 {"PinByName", F_PinByName
},
383 {"PinOrPadName", F_PinOrPadName
},
384 {"Pinout", F_Pinout
},
385 {"Polygon", F_Polygon
},
386 {"PolygonHole", F_PolygonHole
},
387 {"PreviousPoint", F_PreviousPoint
},
388 {"RatsNest", F_RatsNest
},
389 {"Rectangle", F_Rectangle
},
390 {"Redraw", F_Redraw
},
391 {"Release", F_Release
},
392 {"Remove", F_Remove
},
393 {"RemoveSelected", F_RemoveSelected
},
394 {"Report", F_Report
},
396 {"ResetLinesAndPolygons", F_ResetLinesAndPolygons
},
397 {"ResetPinsViasAndPads", F_ResetPinsViasAndPads
},
398 {"Restore", F_Restore
},
399 {"Revert", F_Revert
},
400 {"Rotate", F_Rotate
},
402 {"Selected", F_Selected
},
403 {"SelectedArcs", F_SelectedArcs
},
404 {"SelectedElements", F_SelectedElements
},
405 {"SelectedLines", F_SelectedLines
},
406 {"SelectedNames", F_SelectedNames
},
407 {"SelectedObjects", F_SelectedObjects
},
408 {"SelectedPins", F_SelectedPins
},
409 {"SelectedPads", F_SelectedPads
},
410 {"SelectedRats", F_SelectedRats
},
411 {"SelectedTexts", F_SelectedTexts
},
412 {"SelectedVias", F_SelectedVias
},
413 {"Stroke", F_Stroke
},
415 {"TextByName", F_TextByName
},
416 {"TextScale", F_TextScale
},
417 {"Thermal", F_Thermal
},
418 {"ToLayout", F_ToLayout
},
419 {"Toggle45Degree", F_ToggleAllDirections
},
420 {"ToggleClearLine", F_ToggleClearLine
},
421 {"ToggleFullPoly", F_ToggleFullPoly
},
422 {"ToggleGrid", F_ToggleGrid
},
423 {"ToggleMask", F_ToggleMask
},
424 {"ToggleName", F_ToggleName
},
425 {"ToggleObject", F_ToggleObject
},
426 {"ToggleRubberBandMode", F_ToggleRubberBandMode
},
427 {"ToggleStartDirection", F_ToggleStartDirection
},
428 {"ToggleSnapPin", F_ToggleSnapPin
},
429 {"ToggleThindraw", F_ToggleThindraw
},
430 {"ToggleThindrawPoly", F_ToggleThindrawPoly
},
431 {"ToggleLockNames", F_ToggleLockNames
},
432 {"ToggleOnlyNames", F_ToggleOnlyNames
},
433 {"ToggleHideNames", F_ToggleHideNames
},
434 {"ToggleCheckPlanes", F_ToggleCheckPlanes
},
435 {"ToggleLocalRef", F_ToggleLocalRef
},
436 {"ToggleOrthoMove", F_ToggleOrthoMove
},
437 {"ToggleShowDRC", F_ToggleShowDRC
},
438 {"ToggleLiveRoute", F_ToggleLiveRoute
},
439 {"ToggleAutoDRC", F_ToggleAutoDRC
},
440 {"ToggleUniqueNames", F_ToggleUniqueNames
},
443 {"ViaByName", F_ViaByName
},
444 {"ViaSize", F_ViaSize
},
445 {"ViaDrillingHole", F_ViaDrillingHole
},
449 /* ---------------------------------------------------------------------------
450 * some local routines
452 static int GetFunctionID (String
);
453 static void AdjustAttachedBox (void);
454 static void NotifyLine (void);
455 static void NotifyBlock (void);
456 static void NotifyMode (void);
457 static void ClearWarnings (void);
458 #ifdef HAVE_LIBSTROKE
459 static void FinishStroke (void);
460 extern void stroke_init (void);
461 extern void stroke_record (int x
, int y
);
462 extern int stroke_trans (char *s
);
464 static void ChangeFlag (char *, char *, int, char *);
466 #define ARG(n) (argc > (n) ? argv[n] : NULL)
468 #ifdef HAVE_LIBSTROKE
470 /* ---------------------------------------------------------------------------
471 * FinishStroke - try to recognize the stroke sent
479 void *ptr1
, *ptr2
, *ptr3
;
482 if (stroke_trans (msg
))
488 if (Settings
.Mode
== LINE_MODE
)
498 RotateScreenObject (StrokeBox
.X1
, StrokeBox
.Y1
, SWAP_IDENT
? 1 : 3);
504 RotateScreenObject (StrokeBox
.X1
, StrokeBox
.Y1
, SWAP_IDENT
? 3 : 1);
510 SetMode (ARROW_MODE
);
535 SetZoom (1000); /* special zoom extents */
547 Coord x
= (StrokeBox
.X1
+ StrokeBox
.X2
) / 2;
548 Coord y
= (StrokeBox
.Y1
+ StrokeBox
.Y2
) / 2;
550 /* XXX: PCB->MaxWidth and PCB->MaxHeight may be the wrong
551 * divisors below. The old code WAS broken, but this
552 * replacement has not been tested for correctness.
556 log (fabs (StrokeBox
.X2
- StrokeBox
.X1
) / PCB
->MaxWidth
) /
561 log (fabs (StrokeBox
.Y2
- StrokeBox
.Y1
) / PCB
->MaxHeight
) /
565 CenterDisplay (x
, y
);
570 Message (_("Unknown stroke %s\n"), msg
);
579 /* ---------------------------------------------------------------------------
580 * Clear warning color from pins/pads
585 Settings
.RatWarn
= false;
586 ALLPIN_LOOP (PCB
->Data
);
588 if (TEST_FLAG (WARNFLAG
, pin
))
590 CLEAR_FLAG (WARNFLAG
, pin
);
595 ALLPAD_LOOP (PCB
->Data
);
597 if (TEST_FLAG (WARNFLAG
, pad
))
599 CLEAR_FLAG (WARNFLAG
, pad
);
612 notify_crosshair_change (false);
614 if (Note
.Moving
&& !gui
->shift_is_pressed ())
616 Note
.Buffer
= Settings
.BufferNumber
;
617 SetBufferNumber (MAX_BUFFER
- 1);
618 ClearBuffer (PASTEBUFFER
);
619 AddSelectedToBuffer (PASTEBUFFER
, Note
.X
, Note
.Y
, true);
620 SaveUndoSerialNumber ();
624 SetMode (PASTEBUFFER_MODE
);
626 else if (Note
.Hit
&& !gui
->shift_is_pressed ())
630 SetMode (gui
->control_is_pressed ()? COPY_MODE
: MOVE_MODE
);
631 Crosshair
.AttachedObject
.Ptr1
= Note
.ptr1
;
632 Crosshair
.AttachedObject
.Ptr2
= Note
.ptr2
;
633 Crosshair
.AttachedObject
.Ptr3
= Note
.ptr3
;
634 Crosshair
.AttachedObject
.Type
= Note
.Hit
;
635 AttachForCopy (Note
.X
, Note
.Y
);
643 SaveUndoSerialNumber ();
648 /* unselect first if shift key not down */
649 if (!gui
->shift_is_pressed () && SelectBlock (&box
, false))
650 SetChangedFlag (true);
652 Crosshair
.AttachedBox
.Point1
.X
= Note
.X
;
653 Crosshair
.AttachedBox
.Point1
.Y
= Note
.Y
;
655 notify_crosshair_change (true);
673 Note
.Click
= false; /* inhibit timer action */
674 SaveUndoSerialNumber ();
675 /* unselect first if shift key not down */
676 if (!gui
->shift_is_pressed ())
678 if (SelectBlock (&box
, false))
679 SetChangedFlag (true);
687 RestoreUndoSerialNumber ();
689 SetChangedFlag (true);
693 else if (Note
.Moving
)
695 RestoreUndoSerialNumber ();
697 ClearBuffer (PASTEBUFFER
);
698 SetBufferNumber (Note
.Buffer
);
707 else if (Settings
.Mode
== ARROW_MODE
)
709 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
710 Crosshair
.AttachedBox
.Point2
.X
);
711 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
712 Crosshair
.AttachedBox
.Point2
.Y
);
713 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
714 Crosshair
.AttachedBox
.Point2
.X
);
715 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
716 Crosshair
.AttachedBox
.Point2
.Y
);
717 RestoreUndoSerialNumber ();
718 if (SelectBlock (&box
, true))
719 SetChangedFlag (true);
721 IncrementUndoSerialNumber ();
722 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
729 /* ---------------------------------------------------------------------------
730 * get function ID of passed string
733 static char function_hash
[HSIZE
];
734 static int hash_initted
= 0;
743 i
= (i
* 13) ^ (unsigned char)tolower((int) *s
);
746 i
= (unsigned int)i
% HSIZE
;
751 GetFunctionID (String Ident
)
761 if (HSIZE
< ENTRIES (Functions
) * 2)
763 fprintf(stderr
, _("Error: function hash size too small (%d vs %lu at %s:%d)\n"),
764 HSIZE
, (unsigned long) ENTRIES (Functions
)*2, __FILE__
, __LINE__
);
767 if (ENTRIES (Functions
) > 254)
769 /* Change 'char' to 'int' and remove this when we get to 256
771 fprintf(stderr
, _("Error: function hash type too small (%d vs %lu at %s:%d)\n"),
772 256, (unsigned long) ENTRIES (Functions
), __FILE__
, __LINE__
);
776 for (i
=ENTRIES (Functions
)-1; i
>=0; i
--)
778 h
= hashfunc (Functions
[i
].Identifier
);
779 while (function_hash
[h
])
781 function_hash
[h
] = i
+ 1;
785 i
= hashfunc (Ident
);
788 /* We enforce the "hash table bigger than function table" rule,
789 so we know there will be at least one zero entry to find. */
790 if (!function_hash
[i
])
792 if (!strcasecmp (Ident
, Functions
[function_hash
[i
]-1].Identifier
))
793 return ((int) Functions
[function_hash
[i
]-1].ID
);
798 /* ---------------------------------------------------------------------------
799 * set new coordinates if in 'RECTANGLE' mode
800 * the cursor shape is also adjusted
803 AdjustAttachedBox (void)
805 if (Settings
.Mode
== ARC_MODE
)
807 Crosshair
.AttachedBox
.otherway
= gui
->shift_is_pressed ();
810 switch (Crosshair
.AttachedBox
.State
)
812 case STATE_SECOND
: /* one corner is selected */
814 /* update coordinates */
815 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
816 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
822 /* ---------------------------------------------------------------------------
823 * adjusts the objects which are to be created like attached lines...
826 AdjustAttachedObjects (void)
829 switch (Settings
.Mode
)
831 /* update at least an attached block (selection) */
834 if (Crosshair
.AttachedBox
.State
)
836 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
837 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
841 /* rectangle creation mode */
844 AdjustAttachedBox ();
847 /* polygon creation mode */
849 case POLYGONHOLE_MODE
:
850 AdjustAttachedLine ();
852 /* line creation mode */
854 if (PCB
->RatDraw
|| PCB
->Clipping
== 0)
855 AdjustAttachedLine ();
857 AdjustTwoLine (PCB
->Clipping
- 1);
859 /* point insertion mode */
860 case INSERTPOINT_MODE
:
861 pnt
= AdjustInsertPoint ();
863 InsertedPoint
= *pnt
;
870 /* ---------------------------------------------------------------------------
871 * creates points of a line
877 void *ptr1
, *ptr2
, *ptr3
;
879 if (!Marked
.status
|| TEST_FLAG (LOCALREFFLAG
, PCB
))
880 SetLocalRef (Crosshair
.X
, Crosshair
.Y
, true);
881 switch (Crosshair
.AttachedLine
.State
)
883 case STATE_FIRST
: /* first point */
884 if (PCB
->RatDraw
&& SearchScreen (Crosshair
.X
, Crosshair
.Y
,
885 PAD_TYPE
| PIN_TYPE
, &ptr1
, &ptr1
,
891 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
893 type
= SearchScreen (Crosshair
.X
, Crosshair
.Y
,
894 PIN_TYPE
| PAD_TYPE
| VIA_TYPE
, &ptr1
, &ptr2
,
896 LookupConnection (Crosshair
.X
, Crosshair
.Y
, true, 1,
899 if (type
== PIN_TYPE
|| type
== VIA_TYPE
)
901 Crosshair
.AttachedLine
.Point1
.X
=
902 Crosshair
.AttachedLine
.Point2
.X
= ((PinTypePtr
) ptr2
)->X
;
903 Crosshair
.AttachedLine
.Point1
.Y
=
904 Crosshair
.AttachedLine
.Point2
.Y
= ((PinTypePtr
) ptr2
)->Y
;
906 else if (type
== PAD_TYPE
)
908 PadTypePtr pad
= (PadTypePtr
) ptr2
;
909 double d1
= Distance (Crosshair
.X
, Crosshair
.Y
, pad
->Point1
.X
, pad
->Point1
.Y
);
910 double d2
= Distance (Crosshair
.X
, Crosshair
.Y
, pad
->Point2
.X
, pad
->Point2
.Y
);
913 Crosshair
.AttachedLine
.Point1
=
914 Crosshair
.AttachedLine
.Point2
= pad
->Point2
;
918 Crosshair
.AttachedLine
.Point1
=
919 Crosshair
.AttachedLine
.Point2
= pad
->Point1
;
924 Crosshair
.AttachedLine
.Point1
.X
=
925 Crosshair
.AttachedLine
.Point2
.X
= Crosshair
.X
;
926 Crosshair
.AttachedLine
.Point1
.Y
=
927 Crosshair
.AttachedLine
.Point2
.Y
= Crosshair
.Y
;
929 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
933 /* fall through to third state too */
935 default: /* all following points */
936 Crosshair
.AttachedLine
.State
= STATE_THIRD
;
941 /* ---------------------------------------------------------------------------
942 * create first or second corner of a marked block
947 notify_crosshair_change (false);
948 switch (Crosshair
.AttachedBox
.State
)
950 case STATE_FIRST
: /* setup first point */
951 Crosshair
.AttachedBox
.Point1
.X
=
952 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
953 Crosshair
.AttachedBox
.Point1
.Y
=
954 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
955 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
958 case STATE_SECOND
: /* setup second point */
959 Crosshair
.AttachedBox
.State
= STATE_THIRD
;
962 notify_crosshair_change (true);
966 /* ---------------------------------------------------------------------------
968 * does what's appropriate for the current mode setting. This normally
969 * means creation of an object at the current crosshair location.
971 * new created objects are added to the create undo list of course
976 void *ptr1
, *ptr2
, *ptr3
;
979 if (Settings
.RatWarn
)
981 switch (Settings
.Mode
)
989 /* do something after click time */
990 gui
->add_timer (click_cb
, CLICK_TIME
, hv
);
992 /* see if we clicked on something already selected
993 * (Note.Moving) or clicked on a MOVE_TYPE
996 for (test
= (SELECT_TYPES
| MOVE_TYPES
) & ~RATLINE_TYPE
;
999 type
= SearchScreen (Note
.X
, Note
.Y
, test
, &ptr1
, &ptr2
, &ptr3
);
1000 if (!Note
.Hit
&& (type
& MOVE_TYPES
) &&
1001 !TEST_FLAG (LOCKFLAG
, (PinTypePtr
) ptr2
))
1008 if (!Note
.Moving
&& (type
& SELECT_TYPES
) &&
1009 TEST_FLAG (SELECTEDFLAG
, (PinTypePtr
) ptr2
))
1011 if ((Note
.Hit
&& Note
.Moving
) || type
== NO_TYPE
)
1023 Message (_("You must turn via visibility on before\n"
1024 "you can place vias\n"));
1027 if ((via
= CreateNewVia (PCB
->Data
, Note
.X
, Note
.Y
,
1028 Settings
.ViaThickness
, 2 * Settings
.Keepaway
,
1029 0, Settings
.ViaDrillingHole
, NULL
,
1030 NoFlags ())) != NULL
)
1032 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1033 if (gui
->shift_is_pressed ())
1034 ChangeObjectThermal (VIA_TYPE
, via
, via
, via
, PCB
->ThermStyle
);
1035 IncrementUndoSerialNumber ();
1044 switch (Crosshair
.AttachedBox
.State
)
1047 Crosshair
.AttachedBox
.Point1
.X
=
1048 Crosshair
.AttachedBox
.Point2
.X
= Note
.X
;
1049 Crosshair
.AttachedBox
.Point1
.Y
=
1050 Crosshair
.AttachedBox
.Point2
.Y
= Note
.Y
;
1051 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
1061 wx
= Note
.X
- Crosshair
.AttachedBox
.Point1
.X
;
1062 wy
= Note
.Y
- Crosshair
.AttachedBox
.Point1
.Y
;
1063 if (XOR (Crosshair
.AttachedBox
.otherway
, abs (wy
) > abs (wx
)))
1065 Crosshair
.AttachedBox
.Point2
.X
=
1066 Crosshair
.AttachedBox
.Point1
.X
+ abs (wy
) * SGNZ (wx
);
1067 sa
= (wx
>= 0) ? 0 : 180;
1069 if (abs (wy
) / 2 >= abs (wx
))
1070 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 45 : -45;
1073 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 90 : -90;
1077 Crosshair
.AttachedBox
.Point2
.Y
=
1078 Crosshair
.AttachedBox
.Point1
.Y
+ abs (wx
) * SGNZ (wy
);
1079 sa
= (wy
>= 0) ? -90 : 90;
1081 if (abs (wx
) / 2 >= abs (wy
))
1082 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -45 : 45;
1085 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -90 : 90;
1088 if (abs (wy
) > 0 && (arc
= CreateNewArcOnLayer (CURRENT
,
1112 bx
= GetArcEnds (arc
);
1113 Crosshair
.AttachedBox
.Point1
.X
=
1114 Crosshair
.AttachedBox
.Point2
.X
= bx
->X2
;
1115 Crosshair
.AttachedBox
.Point1
.Y
=
1116 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y2
;
1117 AddObjectToCreateUndoList (ARC_TYPE
, CURRENT
, arc
, arc
);
1118 IncrementUndoSerialNumber ();
1120 DrawArc (CURRENT
, arc
);
1122 Crosshair
.AttachedBox
.State
= STATE_THIRD
;
1131 type
= SearchScreen (Note
.X
, Note
.Y
, LOCK_TYPES
, &ptr1
, &ptr2
, &ptr3
);
1132 if (type
== ELEMENT_TYPE
)
1134 ElementTypePtr element
= (ElementTypePtr
) ptr2
;
1136 TOGGLE_FLAG (LOCKFLAG
, element
);
1139 TOGGLE_FLAG (LOCKFLAG
, pin
);
1140 CLEAR_FLAG (SELECTEDFLAG
, pin
);
1145 TOGGLE_FLAG (LOCKFLAG
, pad
);
1146 CLEAR_FLAG (SELECTEDFLAG
, pad
);
1149 CLEAR_FLAG (SELECTEDFLAG
, element
);
1150 /* always re-draw it since I'm too lazy
1151 * to tell if a selected flag changed
1153 DrawElement (element
);
1155 hid_actionl ("Report", "Object", NULL
);
1157 else if (type
!= NO_TYPE
)
1159 TextTypePtr thing
= (TextTypePtr
) ptr3
;
1160 TOGGLE_FLAG (LOCKFLAG
, thing
);
1161 if (TEST_FLAG (LOCKFLAG
, thing
)
1162 && TEST_FLAG (SELECTEDFLAG
, thing
))
1164 /* this is not un-doable since LOCK isn't */
1165 CLEAR_FLAG (SELECTEDFLAG
, thing
);
1166 DrawObject (type
, ptr1
, ptr2
);
1169 hid_actionl ("Report", "Object", NULL
);
1177 SearchScreen (Note
.X
, Note
.Y
, PIN_TYPES
, &ptr1
, &ptr2
,
1179 && !TEST_FLAG (HOLEFLAG
, (PinTypePtr
) ptr3
))
1181 if (gui
->shift_is_pressed ())
1183 int tstyle
= GET_THERM (INDEXOFCURRENT
, (PinTypePtr
) ptr3
);
1187 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, tstyle
);
1189 else if (GET_THERM (INDEXOFCURRENT
, (PinTypePtr
) ptr3
))
1190 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, 0);
1192 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, PCB
->ThermStyle
);
1198 /* do update of position */
1200 if (Crosshair
.AttachedLine
.State
!= STATE_THIRD
)
1203 /* Remove anchor if clicking on start point;
1204 * this means we can't paint 0 length lines
1205 * which could be used for square SMD pads.
1206 * Instead use a very small delta, or change
1207 * the file after saving.
1209 if (Crosshair
.X
== Crosshair
.AttachedLine
.Point1
.X
1210 && Crosshair
.Y
== Crosshair
.AttachedLine
.Point1
.Y
)
1212 SetMode (LINE_MODE
);
1219 if ((line
= AddNet ()))
1222 AddObjectToCreateUndoList (RATLINE_TYPE
, line
, line
, line
);
1223 IncrementUndoSerialNumber ();
1225 Crosshair
.AttachedLine
.Point1
.X
=
1226 Crosshair
.AttachedLine
.Point2
.X
;
1227 Crosshair
.AttachedLine
.Point1
.Y
=
1228 Crosshair
.AttachedLine
.Point2
.Y
;
1234 /* create line if both ends are determined && length != 0 */
1237 int maybe_found_flag
;
1240 && Crosshair
.AttachedLine
.Point1
.X
==
1241 Crosshair
.AttachedLine
.Point2
.X
1242 && Crosshair
.AttachedLine
.Point1
.Y
==
1243 Crosshair
.AttachedLine
.Point2
.Y
1244 && (Crosshair
.AttachedLine
.Point2
.X
!= Note
.X
1245 || Crosshair
.AttachedLine
.Point2
.Y
!= Note
.Y
))
1247 /* We will only need to paint the second line segment.
1248 Since we only check for vias on the first segment,
1249 swap them so the non-empty segment is the first segment. */
1250 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1251 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1254 if (TEST_FLAG (AUTODRCFLAG
, PCB
)
1255 && ! TEST_SILK_LAYER (CURRENT
))
1256 maybe_found_flag
= FOUNDFLAG
;
1258 maybe_found_flag
= 0;
1260 if ((Crosshair
.AttachedLine
.Point1
.X
!=
1261 Crosshair
.AttachedLine
.Point2
.X
1262 || Crosshair
.AttachedLine
.Point1
.Y
!=
1263 Crosshair
.AttachedLine
.Point2
.Y
)
1265 CreateDrawnLineOnLayer (CURRENT
,
1266 Crosshair
.AttachedLine
.Point1
.X
,
1267 Crosshair
.AttachedLine
.Point1
.Y
,
1268 Crosshair
.AttachedLine
.Point2
.X
,
1269 Crosshair
.AttachedLine
.Point2
.Y
,
1270 Settings
.LineThickness
,
1271 2 * Settings
.Keepaway
,
1272 MakeFlags (maybe_found_flag
|
1275 PCB
) ? CLEARLINEFLAG
:
1281 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1282 DrawLine (CURRENT
, line
);
1283 /* place a via if vias are visible, the layer is
1284 in a new group since the last line and there
1285 isn't a pin already here */
1286 if (PCB
->ViaOn
&& GetLayerGroupNumberByPointer (CURRENT
) !=
1287 GetLayerGroupNumberByPointer (lastLayer
) &&
1288 SearchObjectByLocation (PIN_TYPES
, &ptr1
, &ptr2
, &ptr3
,
1289 Crosshair
.AttachedLine
.Point1
.X
,
1290 Crosshair
.AttachedLine
.Point1
.Y
,
1291 Settings
.ViaThickness
/ 2) ==
1294 CreateNewVia (PCB
->Data
,
1295 Crosshair
.AttachedLine
.Point1
.X
,
1296 Crosshair
.AttachedLine
.Point1
.Y
,
1297 Settings
.ViaThickness
,
1298 2 * Settings
.Keepaway
, 0,
1299 Settings
.ViaDrillingHole
, NULL
,
1300 NoFlags ())) != NULL
)
1302 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1305 /* copy the coordinates */
1306 Crosshair
.AttachedLine
.Point1
.X
=
1307 Crosshair
.AttachedLine
.Point2
.X
;
1308 Crosshair
.AttachedLine
.Point1
.Y
=
1309 Crosshair
.AttachedLine
.Point2
.Y
;
1310 IncrementUndoSerialNumber ();
1311 lastLayer
= CURRENT
;
1313 if (PCB
->Clipping
&& (Note
.X
!= Crosshair
.AttachedLine
.Point2
.X
1315 Crosshair
.AttachedLine
.Point2
.Y
)
1317 CreateDrawnLineOnLayer (CURRENT
,
1318 Crosshair
.AttachedLine
.Point2
.X
,
1319 Crosshair
.AttachedLine
.Point2
.Y
,
1321 Settings
.LineThickness
,
1322 2 * Settings
.Keepaway
,
1323 MakeFlags ((TEST_FLAG
1325 PCB
) ? FOUNDFLAG
: 0) |
1328 PCB
) ? CLEARLINEFLAG
:
1332 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1333 IncrementUndoSerialNumber ();
1334 DrawLine (CURRENT
, line
);
1335 /* move to new start point */
1336 Crosshair
.AttachedLine
.Point1
.X
= Note
.X
;
1337 Crosshair
.AttachedLine
.Point1
.Y
= Note
.Y
;
1338 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1339 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1340 if (TEST_FLAG (SWAPSTARTDIRFLAG
, PCB
))
1349 case RECTANGLE_MODE
:
1350 /* do update of position */
1353 /* create rectangle if both corners are determined
1354 * and width, height are != 0
1356 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
1357 Crosshair
.AttachedBox
.Point1
.X
!= Crosshair
.AttachedBox
.Point2
.X
&&
1358 Crosshair
.AttachedBox
.Point1
.Y
!= Crosshair
.AttachedBox
.Point2
.Y
)
1360 PolygonTypePtr polygon
;
1362 int flags
= CLEARPOLYFLAG
;
1363 if (TEST_FLAG (NEWFULLPOLYFLAG
, PCB
))
1364 flags
|= FULLPOLYFLAG
;
1365 if ((polygon
= CreateNewPolygonFromRectangle (CURRENT
,
1367 AttachedBox
.Point1
.X
,
1369 AttachedBox
.Point1
.Y
,
1371 AttachedBox
.Point2
.X
,
1373 AttachedBox
.Point2
.Y
,
1378 AddObjectToCreateUndoList (POLYGON_TYPE
, CURRENT
,
1380 IncrementUndoSerialNumber ();
1381 DrawPolygon (CURRENT
, polygon
);
1385 /* reset state to 'first corner' */
1386 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
1394 if ((string
= gui
->prompt_for (_("Enter text:"), "")) != NULL
)
1396 if (strlen(string
) > 0)
1399 int flag
= CLEARLINEFLAG
;
1401 if (GetLayerGroupNumberByNumber (INDEXOFCURRENT
) ==
1402 GetLayerGroupNumberByNumber (solder_silk_layer
))
1403 flag
|= ONSOLDERFLAG
;
1404 if ((text
= CreateNewText (CURRENT
, &PCB
->Font
, Note
.X
,
1405 Note
.Y
, 0, Settings
.TextScale
,
1406 string
, MakeFlags (flag
))) != NULL
)
1408 AddObjectToCreateUndoList (TEXT_TYPE
, CURRENT
, text
, text
);
1409 IncrementUndoSerialNumber ();
1410 DrawText (CURRENT
, text
);
1421 PointTypePtr points
= Crosshair
.AttachedPolygon
.Points
;
1422 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1424 /* do update of position; use the 'LINE_MODE' mechanism */
1427 /* check if this is the last point of a polygon */
1429 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1430 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1432 CopyAttachedPolygonToLayer ();
1437 /* create new point if it's the first one or if it's
1438 * different to the last one
1441 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1442 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1444 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1445 Crosshair
.AttachedLine
.Point2
.X
,
1446 Crosshair
.AttachedLine
.Point2
.Y
);
1448 /* copy the coordinates */
1449 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1450 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1455 case POLYGONHOLE_MODE
:
1457 switch (Crosshair
.AttachedObject
.State
)
1459 /* first notify, lookup object */
1461 Crosshair
.AttachedObject
.Type
=
1462 SearchScreen (Note
.X
, Note
.Y
, POLYGON_TYPE
,
1463 &Crosshair
.AttachedObject
.Ptr1
,
1464 &Crosshair
.AttachedObject
.Ptr2
,
1465 &Crosshair
.AttachedObject
.Ptr3
);
1467 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1469 if (TEST_FLAG (LOCKFLAG
, (PolygonTypePtr
)
1470 Crosshair
.AttachedObject
.Ptr2
))
1472 Message (_("Sorry, the object is locked\n"));
1473 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1477 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1481 /* second notify, insert new point into object */
1484 PointTypePtr points
= Crosshair
.AttachedPolygon
.Points
;
1485 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1486 POLYAREA
*original
, *new_hole
, *result
;
1489 /* do update of position; use the 'LINE_MODE' mechanism */
1492 /* check if this is the last point of a polygon */
1494 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1495 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1497 /* Create POLYAREAs from the original polygon
1498 * and the new hole polygon */
1499 original
= PolygonToPoly ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
);
1500 new_hole
= PolygonToPoly (&Crosshair
.AttachedPolygon
);
1502 /* Subtract the hole from the original polygon shape */
1503 poly_Boolean_free (original
, new_hole
, &result
, PBO_SUB
);
1505 /* Convert the resulting polygon(s) into a new set of nodes
1506 * and place them on the page. Delete the original polygon.
1508 SaveUndoSerialNumber ();
1509 Flags
= ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
)->Flags
;
1510 PolyToPolygonsOnLayer (PCB
->Data
, (LayerType
*)Crosshair
.AttachedObject
.Ptr1
,
1512 RemoveObject (POLYGON_TYPE
,
1513 Crosshair
.AttachedObject
.Ptr1
,
1514 Crosshair
.AttachedObject
.Ptr2
,
1515 Crosshair
.AttachedObject
.Ptr3
);
1516 RestoreUndoSerialNumber ();
1517 IncrementUndoSerialNumber ();
1520 /* reset state of attached line */
1521 memset (&Crosshair
.AttachedPolygon
, 0, sizeof (PolygonType
));
1522 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
1528 /* create new point if it's the first one or if it's
1529 * different to the last one
1532 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1533 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1535 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1536 Crosshair
.AttachedLine
.Point2
.X
,
1537 Crosshair
.AttachedLine
.Point2
.Y
);
1539 /* copy the coordinates */
1540 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1541 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1550 case PASTEBUFFER_MODE
:
1552 TextType estr
[MAX_ELEMENTNAMES
];
1553 ElementTypePtr e
= 0;
1555 if (gui
->shift_is_pressed ())
1558 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1560 if (type
== ELEMENT_TYPE
)
1562 e
= (ElementTypePtr
) ptr1
;
1567 memcpy (estr
, e
->Name
,
1568 MAX_ELEMENTNAMES
* sizeof (TextType
));
1569 for (i
= 0; i
< MAX_ELEMENTNAMES
; ++i
)
1570 estr
[i
].TextString
= estr
[i
].TextString
? strdup(estr
[i
].TextString
) : NULL
;
1575 if (CopyPastebufferToLayout (Note
.X
, Note
.Y
))
1576 SetChangedFlag (true);
1580 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1582 if (type
== ELEMENT_TYPE
&& ptr1
)
1585 e
= (ElementTypePtr
) ptr1
;
1587 save_n
= NAME_INDEX (PCB
);
1589 for (i
= 0; i
< MAX_ELEMENTNAMES
; i
++)
1592 EraseElementName (e
);
1593 r_delete_entry (PCB
->Data
->name_tree
[i
],
1594 (BoxType
*) & (e
->Name
[i
]));
1595 memcpy (&(e
->Name
[i
]), &(estr
[i
]), sizeof (TextType
));
1596 e
->Name
[i
].Element
= e
;
1597 SetTextBoundingBox (&PCB
->Font
, &(e
->Name
[i
]));
1598 r_insert_entry (PCB
->Data
->name_tree
[i
],
1599 (BoxType
*) & (e
->Name
[i
]), 0);
1601 DrawElementName (e
);
1610 SearchScreen (Note
.X
, Note
.Y
, REMOVE_TYPES
, &ptr1
, &ptr2
,
1613 if (TEST_FLAG (LOCKFLAG
, (LineTypePtr
) ptr2
))
1615 Message (_("Sorry, the object is locked\n"));
1618 if (type
== ELEMENT_TYPE
)
1620 RubberbandTypePtr ptr
;
1623 Crosshair
.AttachedObject
.RubberbandN
= 0;
1624 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
1625 ptr
= Crosshair
.AttachedObject
.Rubberband
;
1626 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
; i
++)
1629 EraseRat ((RatTypePtr
) ptr
->Line
);
1630 if (TEST_FLAG (RUBBERENDFLAG
, ptr
->Line
))
1631 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
1632 ptr
->Line
, ptr
->Line
,
1635 TOGGLE_FLAG (RUBBERENDFLAG
, ptr
->Line
); /* only remove line once */
1639 RemoveObject (type
, ptr1
, ptr2
, ptr3
);
1640 IncrementUndoSerialNumber ();
1641 SetChangedFlag (true);
1646 RotateScreenObject (Note
.X
, Note
.Y
,
1647 gui
->shift_is_pressed ()? (SWAP_IDENT
?
1649 : (SWAP_IDENT
? 3 : 1));
1652 /* both are almost the same */
1655 switch (Crosshair
.AttachedObject
.State
)
1657 /* first notify, lookup object */
1660 int types
= (Settings
.Mode
== COPY_MODE
) ?
1661 COPY_TYPES
: MOVE_TYPES
;
1663 Crosshair
.AttachedObject
.Type
=
1664 SearchScreen (Note
.X
, Note
.Y
, types
,
1665 &Crosshair
.AttachedObject
.Ptr1
,
1666 &Crosshair
.AttachedObject
.Ptr2
,
1667 &Crosshair
.AttachedObject
.Ptr3
);
1668 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1670 if (Settings
.Mode
== MOVE_MODE
&&
1671 TEST_FLAG (LOCKFLAG
, (PinTypePtr
)
1672 Crosshair
.AttachedObject
.Ptr2
))
1674 Message (_("Sorry, the object is locked\n"));
1675 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1678 AttachForCopy (Note
.X
, Note
.Y
);
1683 /* second notify, move or copy object */
1685 if (Settings
.Mode
== COPY_MODE
)
1686 CopyObject (Crosshair
.AttachedObject
.Type
,
1687 Crosshair
.AttachedObject
.Ptr1
,
1688 Crosshair
.AttachedObject
.Ptr2
,
1689 Crosshair
.AttachedObject
.Ptr3
,
1690 Note
.X
- Crosshair
.AttachedObject
.X
,
1691 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1694 MoveObjectAndRubberband (Crosshair
.AttachedObject
.Type
,
1695 Crosshair
.AttachedObject
.Ptr1
,
1696 Crosshair
.AttachedObject
.Ptr2
,
1697 Crosshair
.AttachedObject
.Ptr3
,
1698 Note
.X
- Crosshair
.AttachedObject
.X
,
1699 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1700 SetLocalRef (0, 0, false);
1702 SetChangedFlag (true);
1704 /* reset identifiers */
1705 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1706 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1711 /* insert a point into a polygon/line/... */
1712 case INSERTPOINT_MODE
:
1713 switch (Crosshair
.AttachedObject
.State
)
1715 /* first notify, lookup object */
1717 Crosshair
.AttachedObject
.Type
=
1718 SearchScreen (Note
.X
, Note
.Y
, INSERT_TYPES
,
1719 &Crosshair
.AttachedObject
.Ptr1
,
1720 &Crosshair
.AttachedObject
.Ptr2
,
1721 &Crosshair
.AttachedObject
.Ptr3
);
1723 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1725 if (TEST_FLAG (LOCKFLAG
, (PolygonTypePtr
)
1726 Crosshair
.AttachedObject
.Ptr2
))
1728 Message (_("Sorry, the object is locked\n"));
1729 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1734 /* get starting point of nearest segment */
1735 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1738 (PolygonTypePtr
) Crosshair
.AttachedObject
.Ptr2
;
1740 GetLowestDistancePolygonPoint (fake
.poly
, Note
.X
,
1742 fake
.line
.Point1
= fake
.poly
->Points
[polyIndex
];
1743 fake
.line
.Point2
= fake
.poly
->Points
[
1744 prev_contour_point (fake
.poly
, polyIndex
)];
1745 Crosshair
.AttachedObject
.Ptr2
= &fake
.line
;
1748 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1749 InsertedPoint
= *AdjustInsertPoint ();
1754 /* second notify, insert new point into object */
1756 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1757 InsertPointIntoObject (POLYGON_TYPE
,
1758 Crosshair
.AttachedObject
.Ptr1
, fake
.poly
,
1760 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1762 InsertPointIntoObject (Crosshair
.AttachedObject
.Type
,
1763 Crosshair
.AttachedObject
.Ptr1
,
1764 Crosshair
.AttachedObject
.Ptr2
,
1766 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1767 SetChangedFlag (true);
1769 /* reset identifiers */
1770 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1771 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1779 /* --------------------------------------------------------------------------- */
1781 static const char atomic_syntax
[] = "Atomic(Save|Restore|Close|Block)";
1783 static const char atomic_help
[] = "Save or restore the undo serial number.";
1785 /* %start-doc actions Atomic
1787 This action allows making multiple-action bindings into an atomic
1788 operation that will be undone by a single Undo command. For example,
1789 to optimize rat lines, you'd delete the rats and re-add them. To
1790 group these into a single undo, you'd want the deletions and the
1791 additions to have the same undo serial number. So, you @code{Save},
1792 delete the rats, @code{Restore}, add the rats - using the same serial
1793 number as the deletes, then @code{Block}, which checks to see if the
1794 deletions or additions actually did anything. If not, the serial
1795 number is set to the saved number, as there's nothing to undo. If
1796 something did happen, the serial number is incremented so that these
1797 actions are counted as a single undo step.
1802 Saves the undo serial number.
1805 Returns it to the last saved number.
1808 Sets it to 1 greater than the last save.
1811 Does a Restore if there was nothing to undo, else does a Close.
1818 ActionAtomic (int argc
, char **argv
, Coord x
, Coord y
)
1823 switch (GetFunctionID (argv
[0]))
1826 SaveUndoSerialNumber ();
1829 RestoreUndoSerialNumber ();
1832 RestoreUndoSerialNumber ();
1833 IncrementUndoSerialNumber ();
1836 RestoreUndoSerialNumber ();
1838 IncrementUndoSerialNumber ();
1844 /* -------------------------------------------------------------------------- */
1846 static const char drc_syntax
[] = "DRC()";
1848 static const char drc_help
[] = "Invoke the DRC check.";
1850 /* %start-doc actions DRC
1852 Note that the design rule check uses the current board rule settings,
1853 not the current style settings.
1858 ActionDRCheck (int argc
, char **argv
, Coord x
, Coord y
)
1862 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1864 Message (_("%m+Rules are minspace %$mS, minoverlap %$mS "
1865 "minwidth %$mS, minsilk %$mS\n"
1866 "min drill %$mS, min annular ring %$mS\n"),
1867 Settings
.grid_unit
->allow
,
1868 PCB
->Bloat
, PCB
->Shrink
,
1869 PCB
->minWid
, PCB
->minSlk
,
1870 PCB
->minDrill
, PCB
->minRing
);
1873 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1876 Message (_("No DRC problems found.\n"));
1878 Message (_("Found %d design rule errors.\n"), count
);
1880 Message (_("Aborted DRC after %d design rule errors.\n"), -count
);
1885 /* -------------------------------------------------------------------------- */
1887 static const char dumplibrary_syntax
[] = "DumpLibrary()";
1889 static const char dumplibrary_help
[] =
1890 "Display the entire contents of the libraries.";
1892 /* %start-doc actions DumpLibrary
1898 ActionDumpLibrary (int argc
, char **argv
, Coord x
, Coord y
)
1902 printf ("**** Do not count on this format. It will change ****\n\n");
1903 printf ("MenuN = %d\n", Library
.MenuN
);
1904 printf ("MenuMax = %d\n", Library
.MenuMax
);
1905 for (i
= 0; i
< Library
.MenuN
; i
++)
1907 printf ("Library #%d:\n", i
);
1908 printf (" EntryN = %d\n", Library
.Menu
[i
].EntryN
);
1909 printf (" EntryMax = %d\n", Library
.Menu
[i
].EntryMax
);
1910 printf (" Name = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Name
));
1911 printf (" directory = \"%s\"\n",
1912 UNKNOWN (Library
.Menu
[i
].directory
));
1913 printf (" Style = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Style
));
1914 printf (" flag = %d\n", Library
.Menu
[i
].flag
);
1916 for (j
= 0; j
< Library
.Menu
[i
].EntryN
; j
++)
1918 printf (" #%4d: ", j
);
1919 if (Library
.Menu
[i
].Entry
[j
].Template
== (char *) -1)
1921 printf ("newlib: \"%s\"\n",
1922 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
));
1926 printf ("\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"\n",
1927 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
),
1928 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Template
),
1929 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Package
),
1930 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Value
),
1931 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Description
));
1939 /* -------------------------------------------------------------------------- */
1941 static const char flip_syntax
[] = "Flip(Object|Selected|SelectedElements)";
1943 static const char flip_help
[] =
1944 "Flip an element to the opposite side of the board.";
1946 /* %start-doc actions Flip
1948 Note that the location of the element will be symmetric about the
1949 cursor location; i.e. if the part you are pointing at will still be at
1950 the same spot once the element is on the other side. When flipping
1951 multiple elements, this retains their positions relative to each
1952 other, not their absolute positions on the board.
1957 ActionFlip (int argc
, char **argv
, Coord x
, Coord y
)
1959 char *function
= ARG (0);
1960 ElementTypePtr element
;
1966 switch (GetFunctionID (function
))
1969 if ((SearchScreen (x
, y
, ELEMENT_TYPE
,
1970 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
1972 element
= (ElementTypePtr
) ptrtmp
;
1973 ChangeElementSide (element
, 2 * Crosshair
.Y
- PCB
->MaxHeight
);
1974 IncrementUndoSerialNumber ();
1979 case F_SelectedElements
:
1980 ChangeSelectedElementSide ();
1993 /* -------------------------------------------------------------------------- */
1995 static const char message_syntax
[] = "Message(message)";
1997 static const char message_help
[] = "Writes a message to the log window.";
1999 /* %start-doc actions Message
2001 This action displays a message to the log window. This action is primarily
2002 provided for use by other programs which may interface with PCB. If
2003 multiple arguments are given, each one is sent to the log window
2004 followed by a newline.
2009 ActionMessage (int argc
, char **argv
, Coord x
, Coord y
)
2016 for (i
= 0; i
< argc
; i
++)
2026 /* -------------------------------------------------------------------------- */
2028 static const char setthermal_syntax
[] =
2029 "SetThermal(Object|SelectedPins|SelectedVias|Selected, Style)";
2031 static const char setthermal_help
[] =
2032 "Set the thermal (on the current layer) of pins or vias to the given style.\n"
2033 "Style = 0 means no thermal.\n"
2034 "Style = 1 has diagonal fingers with sharp edges.\n"
2035 "Style = 2 has horizontal and vertical fingers with sharp edges.\n"
2036 "Style = 3 is a solid connection to the plane."
2037 "Style = 4 has diagonal fingers with rounded edges.\n"
2038 "Style = 5 has horizontal and vertical fingers with rounded edges.\n";
2040 /* %start-doc actions SetThermal
2042 This changes how/whether pins or vias connect to any rectangle or polygon
2043 on the current layer. The first argument can specify one object, or all
2044 selected pins, or all selected vias, or all selected pins and vias.
2045 The second argument specifies the style of connection.
2046 There are 5 possibilities:
2048 1 - 45 degree fingers with sharp edges,
2049 2 - horizontal & vertical fingers with sharp edges,
2050 3 - solid connection,
2051 4 - 45 degree fingers with rounded corners,
2052 5 - horizontal & vertical fingers with rounded corners.
2054 Pins and Vias may have thermals whether or not there is a polygon available
2055 to connect with. However, they will have no effect without the polygon.
2059 ActionSetThermal (int argc
, char **argv
, Coord x
, Coord y
)
2061 char *function
= ARG (0);
2062 char *style
= ARG (1);
2063 void *ptr1
, *ptr2
, *ptr3
;
2067 if (function
&& *function
&& style
&& *style
)
2071 kind
= GetValue (style
, NULL
, &absolute
);
2073 switch (GetFunctionID (function
))
2077 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGETHERMAL_TYPES
,
2078 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
2080 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, kind
);
2081 IncrementUndoSerialNumber ();
2085 case F_SelectedPins
:
2086 ChangeSelectedThermals (PIN_TYPE
, kind
);
2088 case F_SelectedVias
:
2089 ChangeSelectedThermals (VIA_TYPE
, kind
);
2092 case F_SelectedElements
:
2093 ChangeSelectedThermals (CHANGETHERMAL_TYPES
, kind
);
2108 /* ---------------------------------------------------------------------------
2109 * !!! no action routine !!!
2111 * event handler to set the cursor according to the X pointer position
2112 * called from inside main.c
2115 EventMoveCrosshair (int ev_x
, int ev_y
)
2117 #ifdef HAVE_LIBSTROKE
2120 StrokeBox
.X2
= ev_x
;
2121 StrokeBox
.Y2
= ev_y
;
2122 stroke_record (ev_x
, ev_y
);
2125 #endif /* HAVE_LIBSTROKE */
2126 if (MoveCrosshairAbsolute (ev_x
, ev_y
))
2128 /* update object position and cursor location */
2129 AdjustAttachedObjects ();
2130 notify_crosshair_change (true);
2134 /* --------------------------------------------------------------------------- */
2136 static const char setvalue_syntax
[] =
2137 "SetValue(Grid|Line|LineSize|Text|TextScale|ViaDrillingHole|Via|ViaSize, delta)";
2139 static const char setvalue_help
[] =
2140 "Change various board-wide values and sizes.";
2142 /* %start-doc actions SetValue
2146 @item ViaDrillingHole
2147 Changes the diameter of the drill for new vias.
2150 Sets the grid spacing.
2154 Changes the thickness of new lines.
2158 Changes the diameter of new vias.
2162 Changes the size of new text.
2169 ActionSetValue (int argc
, char **argv
, Coord x
, Coord y
)
2171 char *function
= ARG (0);
2172 char *val
= ARG (1);
2173 char *units
= ARG (2);
2174 bool absolute
; /* flag for 'absolute' value */
2178 if (function
&& val
)
2180 value
= GetValue (val
, units
, &absolute
);
2181 switch (GetFunctionID (function
))
2183 case F_ViaDrillingHole
:
2184 SetViaDrillingHole (absolute
? value
:
2185 value
+ Settings
.ViaDrillingHole
,
2187 hid_action ("RouteStylesChanged");
2192 SetGrid (value
, false);
2195 /* On the way down, short against the minimum
2196 * PCB drawing unit */
2197 if ((value
+ PCB
->Grid
) < 1)
2199 else if (PCB
->Grid
== 1)
2200 SetGrid (value
, false);
2202 SetGrid (value
+ PCB
->Grid
, false);
2208 SetLineSize (absolute
? value
: value
+ Settings
.LineThickness
);
2209 hid_action ("RouteStylesChanged");
2214 SetViaSize (absolute
? value
: value
+ Settings
.ViaThickness
, false);
2215 hid_action ("RouteStylesChanged");
2221 SetTextScale (absolute
? value
: value
+ Settings
.TextScale
);
2235 /* --------------------------------------------------------------------------- */
2237 static const char quit_syntax
[] = "Quit()";
2239 static const char quit_help
[] = "Quits the application after confirming.";
2241 /* %start-doc actions Quit
2243 If you have unsaved changes, you will be prompted to confirm (or
2244 save) before quitting.
2249 ActionQuit (int argc
, char **argv
, Coord x
, Coord y
)
2251 char *force
= ARG (0);
2252 if (force
&& strcasecmp (force
, "force") == 0)
2257 if (!PCB
->Changed
|| gui
->close_confirm_dialog () == HID_CLOSE_CONFIRM_OK
)
2262 /* --------------------------------------------------------------------------- */
2264 static const char connection_syntax
[] =
2265 "Connection(Find|ResetLinesAndPolygons|ResetPinsAndVias|Reset)";
2267 static const char connection_help
[] =
2268 "Searches connections of the object at the cursor position.";
2270 /* %start-doc actions Connection
2272 Connections found with this action will be highlighted in the
2273 ``connected-color'' color and will have the ``found'' flag set.
2278 The net under the cursor is ``found''.
2280 @item ResetLinesAndPolygons
2281 Any ``found'' lines and polygons are marked ``not found''.
2283 @item ResetPinsAndVias
2284 Any ``found'' pins and vias are marked ``not found''.
2287 All ``found'' objects are marked ``not found''.
2294 ActionConnection (int argc
, char **argv
, Coord x
, Coord y
)
2296 char *function
= ARG (0);
2299 switch (GetFunctionID (function
))
2303 gui
->get_coords (_("Click on a connection"), &x
, &y
);
2304 LookupConnection (x
, y
, true, 1, FOUNDFLAG
);
2308 case F_ResetLinesAndPolygons
:
2309 if (ResetFoundLinesAndPolygons (true))
2311 IncrementUndoSerialNumber ();
2316 case F_ResetPinsViasAndPads
:
2317 if (ResetFoundPinsViasAndPads (true))
2319 IncrementUndoSerialNumber ();
2325 if (ResetConnections (true))
2327 IncrementUndoSerialNumber ();
2338 /* --------------------------------------------------------------------------- */
2340 static const char disperseelements_syntax
[] =
2341 "DisperseElements(All|Selected)";
2343 static const char disperseelements_help
[] = "Disperses elements.";
2345 /* %start-doc actions DisperseElements
2347 Normally this is used when starting a board, by selecting all elements
2348 and then dispersing them. This scatters the elements around the board
2349 so that you can pick individual ones, rather than have all the
2350 elements at the same 0,0 coordinate and thus impossible to choose
2355 #define GAP MIL_TO_COORD(100)
2358 ActionDisperseElements (int argc
, char **argv
, Coord x
, Coord y
)
2360 char *function
= ARG (0);
2365 int all
= 0, bad
= 0;
2367 if (!function
|| !*function
)
2373 switch (GetFunctionID (function
))
2390 AFAIL (disperseelements
);
2394 ELEMENT_LOOP (PCB
->Data
);
2397 * If we want to disperse selected elements, maybe we need smarter
2398 * code here to avoid putting components on top of others which
2399 * are not selected. For now, I'm assuming that this is typically
2400 * going to be used either with a brand new design or a scratch
2401 * design holding some new components
2403 if (!TEST_FLAG (LOCKFLAG
, element
) && (all
|| TEST_FLAG (SELECTEDFLAG
, element
)))
2406 /* figure out how much to move the element */
2407 dx
= minx
- element
->BoundingBox
.X1
;
2409 /* snap to the grid */
2410 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2413 * and add one grid size so we make sure we always space by GAP or
2418 /* Figure out if this row has room. If not, start a new row */
2419 if (GAP
+ element
->BoundingBox
.X2
+ dx
> PCB
->MaxWidth
)
2425 /* figure out how much to move the element */
2426 dx
= minx
- element
->BoundingBox
.X1
;
2427 dy
= miny
- element
->BoundingBox
.Y1
;
2429 /* snap to the grid */
2430 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2432 dy
-= (element
->MarkY
+ dy
) % PCB
->Grid
;
2435 /* move the element */
2436 MoveElementLowLevel (PCB
->Data
, element
, dx
, dy
);
2438 /* and add to the undo list so we can undo this operation */
2439 AddObjectToMoveUndoList (ELEMENT_TYPE
, NULL
, NULL
, element
, dx
, dy
);
2441 /* keep track of how tall this row is */
2442 minx
+= element
->BoundingBox
.X2
- element
->BoundingBox
.X1
+ GAP
;
2443 if (maxy
< element
->BoundingBox
.Y2
)
2445 maxy
= element
->BoundingBox
.Y2
;
2452 /* done with our action so increment the undo # */
2453 IncrementUndoSerialNumber ();
2456 SetChangedFlag (true);
2463 /* --------------------------------------------------------------------------- */
2465 static const char display_syntax
[] =
2466 "Display(NameOnPCB|Description|Value)\n"
2467 "Display(Grid|Redraw)\n"
2468 "Display(CycleClip|CycleCrosshair|Toggle45Degree|ToggleStartDirection)\n"
2469 "Display(ToggleGrid|ToggleRubberBandMode|ToggleUniqueNames)\n"
2470 "Display(ToggleMask|ToggleName|ToggleClearLine|ToggleFullPoly|ToggleSnapPin)\n"
2471 "Display(ToggleThindraw|ToggleThindrawPoly|ToggleOrthoMove|ToggleLocalRef)\n"
2472 "Display(ToggleCheckPlanes|ToggleShowDRC|ToggleAutoDRC)\n"
2473 "Display(ToggleLiveRoute|LockNames|OnlyNames)\n"
2474 "Display(Pinout|PinOrPadName)";
2476 static const char display_help
[] = "Several display-related actions.";
2478 /* %start-doc actions Display
2485 Specify whether all elements show their name, description, or value.
2488 Redraw the whole board.
2490 @item Toggle45Degree
2491 When clear, lines can be drawn at any angle. When set, lines are
2492 restricted to multiples of 45 degrees and requested lines may be
2493 broken up according to the clip setting.
2496 Changes the way lines are restricted to 45 degree increments. The
2497 various settings are: straight only, orthogonal then angled, and angled
2498 then orthogonal. If AllDirections is set, this action disables it.
2500 @item CycleCrosshair
2501 Changes crosshair drawing. Crosshair may accept form of 4-ray,
2502 8-ray and 12-ray cross.
2504 @item ToggleRubberBandMode
2505 If set, moving an object moves all the lines attached to it too.
2507 @item ToggleStartDirection
2508 If set, each time you set a point in a line, the Clip toggles between
2509 orth-angle and angle-ortho.
2511 @item ToggleUniqueNames
2512 If set, you will not be permitted to change the name of an element to
2513 match that of another element.
2516 If set, pin centers and pad end points are treated as additional grid
2517 points that the cursor can snap to.
2519 @item ToggleLocalRef
2520 If set, the mark is automatically set to the beginning of any move, so
2521 you can see the relative distance you've moved.
2523 @item ToggleThindraw
2524 If set, objects on the screen are drawn as outlines (lines are drawn
2525 as center-lines). This lets you see line endpoints hidden under pins,
2528 @item ToggleThindrawPoly
2529 If set, polygons on the screen are drawn as outlines.
2532 If set, pending objects (i.e. lines you're in the process of drawing)
2533 will be drawn with an outline showing how far away from other copper
2536 @item ToggleLiveRoute
2537 If set, the progress of the autorouter will be visible on the screen.
2540 If set, you will not be permitted to make connections which violate
2541 the current DRC and netlist settings.
2543 @item ToggleCheckPlanes
2544 If set, lines and arcs aren't drawn, which usually leaves just the
2545 polygons. If you also disable all but the layer you're interested in,
2546 this allows you to check for isolated regions.
2548 @item ToggleOrthoMove
2549 If set, the crosshair is only allowed to move orthogonally from its
2550 previous position. I.e. you can move an element or line up, down,
2551 left, or right, but not up+left or down+right.
2554 Selects whether the pinouts show the pin names or the pin numbers.
2556 @item ToggleLockNames
2557 If set, text will ignore left mouse clicks and actions that work on
2558 objects under the mouse. You can still select text with a lasso (left
2559 mouse drag) and perform actions on the selection.
2561 @item ToggleOnlyNames
2562 If set, only text will be sensitive for mouse clicks and actions that
2563 work on objects under the mouse. You can still select other objects
2564 with a lasso (left mouse drag) and perform actions on the selection.
2567 Turns the solder mask on or off.
2569 @item ToggleClearLine
2570 When set, the clear-line flag causes new lines and arcs to have their
2571 ``clear polygons'' flag set, so they won't be electrically connected
2572 to any polygons they overlap.
2574 @item ToggleFullPoly
2575 When set, the full-poly flag causes new polygons to have their
2576 ``full polygon'' flag set, so all parts of them will be displayed
2577 instead of only the biggest one.
2580 Resets the origin of the current grid to be wherever the mouse pointer
2581 is (not where the crosshair currently is). If you provide two numbers
2582 after this, the origin is set to that coordinate.
2585 Toggles whether the grid is displayed or not.
2588 Causes the pinout of the element indicated by the cursor to be
2589 displayed, usually in a separate window.
2592 Toggles whether the names of pins, pads, or (yes) vias will be
2593 displayed. If the cursor is over an element, all of its pins and pads
2600 static enum crosshair_shape
2601 CrosshairShapeIncrement (enum crosshair_shape shape
)
2605 case Basic_Crosshair_Shape
:
2606 shape
= Union_Jack_Crosshair_Shape
;
2608 case Union_Jack_Crosshair_Shape
:
2609 shape
= Dozen_Crosshair_Shape
;
2611 case Dozen_Crosshair_Shape
:
2612 shape
= Crosshair_Shapes_Number
;
2614 case Crosshair_Shapes_Number
:
2615 shape
= Basic_Crosshair_Shape
;
2622 ActionDisplay (int argc
, char **argv
, Coord childX
, Coord childY
)
2624 char *function
, *str_dir
;
2631 if (function
&& (!str_dir
|| !*str_dir
))
2633 switch (id
= GetFunctionID (function
))
2637 case F_ClearAndRedraw
:
2642 /* change the displayed name of elements */
2646 ELEMENT_LOOP (PCB
->Data
);
2648 EraseElementName (element
);
2651 CLEAR_FLAG (DESCRIPTIONFLAG
| NAMEONPCBFLAG
, PCB
);
2657 SET_FLAG (NAMEONPCBFLAG
, PCB
);
2660 SET_FLAG (DESCRIPTIONFLAG
, PCB
);
2663 ELEMENT_LOOP (PCB
->Data
);
2665 DrawElementName (element
);
2671 /* toggle line-adjust flag */
2672 case F_ToggleAllDirections
:
2673 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2674 AdjustAttachedObjects ();
2678 notify_crosshair_change (false);
2680 (ALLDIRECTIONFLAG
, PCB
)
2682 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2686 PCB
->Clipping
= (PCB
->Clipping
+ 1) % 3;
2687 AdjustAttachedObjects ();
2688 notify_crosshair_change (true);
2691 case F_CycleCrosshair
:
2692 notify_crosshair_change (false);
2693 Crosshair
.shape
= CrosshairShapeIncrement(Crosshair
.shape
);
2694 if (Crosshair_Shapes_Number
== Crosshair
.shape
)
2695 Crosshair
.shape
= Basic_Crosshair_Shape
;
2696 notify_crosshair_change (true);
2699 case F_ToggleRubberBandMode
:
2700 notify_crosshair_change (false);
2701 TOGGLE_FLAG (RUBBERBANDFLAG
, PCB
);
2702 notify_crosshair_change (true);
2705 case F_ToggleStartDirection
:
2706 notify_crosshair_change (false);
2707 TOGGLE_FLAG (SWAPSTARTDIRFLAG
, PCB
);
2708 notify_crosshair_change (true);
2711 case F_ToggleUniqueNames
:
2712 TOGGLE_FLAG (UNIQUENAMEFLAG
, PCB
);
2715 case F_ToggleSnapPin
:
2716 notify_crosshair_change (false);
2717 TOGGLE_FLAG (SNAPPINFLAG
, PCB
);
2718 notify_crosshair_change (true);
2721 case F_ToggleLocalRef
:
2722 TOGGLE_FLAG (LOCALREFFLAG
, PCB
);
2725 case F_ToggleThindraw
:
2726 TOGGLE_FLAG (THINDRAWFLAG
, PCB
);
2730 case F_ToggleThindrawPoly
:
2731 TOGGLE_FLAG (THINDRAWPOLYFLAG
, PCB
);
2735 case F_ToggleLockNames
:
2736 TOGGLE_FLAG (LOCKNAMESFLAG
, PCB
);
2737 CLEAR_FLAG (ONLYNAMESFLAG
, PCB
);
2740 case F_ToggleOnlyNames
:
2741 TOGGLE_FLAG (ONLYNAMESFLAG
, PCB
);
2742 CLEAR_FLAG (LOCKNAMESFLAG
, PCB
);
2745 case F_ToggleHideNames
:
2746 TOGGLE_FLAG (HIDENAMESFLAG
, PCB
);
2750 case F_ToggleShowDRC
:
2751 TOGGLE_FLAG (SHOWDRCFLAG
, PCB
);
2754 case F_ToggleLiveRoute
:
2755 TOGGLE_FLAG (LIVEROUTEFLAG
, PCB
);
2758 case F_ToggleAutoDRC
:
2759 notify_crosshair_change (false);
2760 TOGGLE_FLAG (AUTODRCFLAG
, PCB
);
2761 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
2763 if (ResetConnections (true))
2765 IncrementUndoSerialNumber ();
2768 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
2769 LookupConnection (Crosshair
.AttachedLine
.Point1
.X
,
2770 Crosshair
.AttachedLine
.Point1
.Y
, true, 1,
2773 notify_crosshair_change (true);
2776 case F_ToggleCheckPlanes
:
2777 TOGGLE_FLAG (CHECKPLANESFLAG
, PCB
);
2781 case F_ToggleOrthoMove
:
2782 TOGGLE_FLAG (ORTHOMOVEFLAG
, PCB
);
2786 TOGGLE_FLAG (SHOWNUMBERFLAG
, PCB
);
2791 TOGGLE_FLAG (SHOWMASKFLAG
, PCB
);
2795 case F_ToggleClearLine
:
2796 TOGGLE_FLAG (CLEARNEWFLAG
, PCB
);
2799 case F_ToggleFullPoly
:
2800 TOGGLE_FLAG (NEWFULLPOLYFLAG
, PCB
);
2803 /* shift grid alignment */
2806 Coord oldGrid
= PCB
->Grid
;
2809 if (MoveCrosshairAbsolute (Crosshair
.X
, Crosshair
.Y
))
2810 notify_crosshair_change (true); /* first notify was in MoveCrosshairAbs */
2811 SetGrid (oldGrid
, true);
2815 /* toggle displaying of the grid */
2817 Settings
.DrawGrid
= !Settings
.DrawGrid
;
2821 /* display the pinout of an element */
2824 ElementTypePtr element
;
2828 gui
->get_coords (_("Click on an element"), &x
, &y
);
2830 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
2831 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
2833 element
= (ElementTypePtr
) ptrtmp
;
2834 gui
->show_item (element
);
2839 /* toggle displaying of pin/pad/via names */
2840 case F_PinOrPadName
:
2842 void *ptr1
, *ptr2
, *ptr3
;
2844 switch (SearchScreen (Crosshair
.X
, Crosshair
.Y
,
2845 ELEMENT_TYPE
| PIN_TYPE
| PAD_TYPE
|
2846 VIA_TYPE
, (void **) &ptr1
, (void **) &ptr2
,
2850 PIN_LOOP ((ElementTypePtr
) ptr1
);
2852 if (TEST_FLAG (DISPLAYNAMEFLAG
, pin
))
2856 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, pin
, pin
);
2857 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pin
);
2860 PAD_LOOP ((ElementTypePtr
) ptr1
);
2862 if (TEST_FLAG (DISPLAYNAMEFLAG
, pad
))
2866 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, pad
, pad
);
2867 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pad
);
2870 SetChangedFlag (true);
2871 IncrementUndoSerialNumber ();
2876 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinTypePtr
) ptr2
))
2877 ErasePinName ((PinTypePtr
) ptr2
);
2879 DrawPinName ((PinTypePtr
) ptr2
);
2880 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, ptr2
, ptr3
);
2881 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinTypePtr
) ptr2
);
2882 SetChangedFlag (true);
2883 IncrementUndoSerialNumber ();
2888 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PadTypePtr
) ptr2
))
2889 ErasePadName ((PadTypePtr
) ptr2
);
2891 DrawPadName ((PadTypePtr
) ptr2
);
2892 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, ptr2
, ptr3
);
2893 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PadTypePtr
) ptr2
);
2894 SetChangedFlag (true);
2895 IncrementUndoSerialNumber ();
2899 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinTypePtr
) ptr2
))
2900 EraseViaName ((PinTypePtr
) ptr2
);
2902 DrawViaName ((PinTypePtr
) ptr2
);
2903 AddObjectToFlagUndoList (VIA_TYPE
, ptr1
, ptr2
, ptr3
);
2904 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinTypePtr
) ptr2
);
2905 SetChangedFlag (true);
2906 IncrementUndoSerialNumber ();
2916 else if (function
&& str_dir
)
2918 switch (GetFunctionID (function
))
2923 PCB
->GridOffsetX
= GetValue (argv
[1], NULL
, NULL
);
2924 PCB
->GridOffsetY
= GetValue (argv
[2], NULL
, NULL
);
2925 if (Settings
.DrawGrid
)
2942 /* --------------------------------------------------------------------------- */
2944 static const char mode_syntax
[] =
2945 "Mode(Arc|Arrow|Copy|InsertPoint|Line|Lock|Move|None|PasteBuffer)\n"
2946 "Mode(Polygon|Rectangle|Remove|Rotate|Text|Thermal|Via)\n"
2947 "Mode(Notify|Release|Cancel|Stroke)\n"
2948 "Mode(Save|Restore)";
2950 static const char mode_help
[] = "Change or use the tool mode.";
2952 /* %start-doc actions Mode
2972 Select the indicated tool.
2975 Called when you press the mouse button, or move the mouse.
2978 Called when you release the mouse button.
2981 Cancels any pending tool activity, allowing you to restart elsewhere.
2982 For example, this allows you to start a new line rather than attach a
2983 line to the previous line.
2986 Similar to Cancel but calling this action a second time will return
2990 If your @code{pcb} was built with libstroke, this invokes the stroke
2991 input method. If not, this will restart a drawing mode if you were
2992 drawing, else it will select objects.
2995 Remembers the current tool.
2998 Restores the tool to the last saved tool.
3005 ActionMode (int argc
, char **argv
, Coord x
, Coord y
)
3007 char *function
= ARG (0);
3011 Note
.X
= Crosshair
.X
;
3012 Note
.Y
= Crosshair
.Y
;
3013 notify_crosshair_change (false);
3014 switch (GetFunctionID (function
))
3020 SetMode (ARROW_MODE
);
3023 SetMode (COPY_MODE
);
3026 SetMode (INSERTPOINT_MODE
);
3029 SetMode (LINE_MODE
);
3032 SetMode (LOCK_MODE
);
3035 SetMode (MOVE_MODE
);
3042 int saved_mode
= Settings
.Mode
;
3044 SetMode (saved_mode
);
3049 switch (Settings
.Mode
)
3052 case PASTEBUFFER_MODE
:
3058 case INSERTPOINT_MODE
:
3059 case RUBBERBANDMOVE_MODE
:
3063 SetMode (ARROW_MODE
);
3067 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3068 SetMode (ARROW_MODE
);
3072 SetMode (LINE_MODE
);
3076 case RECTANGLE_MODE
:
3077 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3078 SetMode (ARROW_MODE
);
3082 SetMode (RECTANGLE_MODE
);
3087 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3088 SetMode (ARROW_MODE
);
3092 SetMode (POLYGON_MODE
);
3096 case POLYGONHOLE_MODE
:
3097 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3098 SetMode (ARROW_MODE
);
3102 SetMode (POLYGONHOLE_MODE
);
3107 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3108 SetMode (ARROW_MODE
);
3129 SetMode (PASTEBUFFER_MODE
);
3132 SetMode (POLYGON_MODE
);
3135 SetMode (POLYGONHOLE_MODE
);
3137 #ifndef HAVE_LIBSTROKE
3150 SetMode (REMOVE_MODE
);
3153 SetMode (RECTANGLE_MODE
);
3156 SetMode (ROTATE_MODE
);
3159 #ifdef HAVE_LIBSTROKE
3161 StrokeBox
.X1
= Crosshair
.X
;
3162 StrokeBox
.Y1
= Crosshair
.Y
;
3165 /* Handle middle mouse button restarts of drawing mode. If not in
3166 | a drawing mode, middle mouse button will select objects.
3168 if (Settings
.Mode
== LINE_MODE
3169 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3171 SetMode (LINE_MODE
);
3173 else if (Settings
.Mode
== ARC_MODE
3174 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3176 else if (Settings
.Mode
== RECTANGLE_MODE
3177 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3178 SetMode (RECTANGLE_MODE
);
3179 else if (Settings
.Mode
== POLYGON_MODE
3180 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3181 SetMode (POLYGON_MODE
);
3186 SetMode (ARROW_MODE
);
3192 SetMode (TEXT_MODE
);
3195 SetMode (THERMAL_MODE
);
3201 case F_Restore
: /* restore the last saved mode */
3205 case F_Save
: /* save currently selected mode */
3209 notify_crosshair_change (true);
3216 /* --------------------------------------------------------------------------- */
3218 static const char removeselected_syntax
[] = "RemoveSelected()";
3220 static const char removeselected_help
[] = "Removes any selected objects.";
3222 /* %start-doc actions RemoveSelected
3227 ActionRemoveSelected (int argc
, char **argv
, Coord x
, Coord y
)
3229 if (RemoveSelected ())
3230 SetChangedFlag (true);
3234 /* --------------------------------------------------------------------------- */
3236 static const char renumber_syntax
[] = "Renumber()\n"
3237 "Renumber(filename)";
3239 static const char renumber_help
[] =
3240 "Renumber all elements. The changes will be recorded to filename\n"
3241 "for use in backannotating these changes to the schematic.";
3243 /* %start-doc actions Renumber
3248 ActionRenumber (int argc
, char **argv
, Coord x
, Coord y
)
3250 bool changed
= false;
3251 ElementTypePtr
*element_list
;
3252 ElementTypePtr
*locked_element_list
;
3253 unsigned int i
, j
, k
, cnt
, lock_cnt
;
3259 static char * default_file
= NULL
;
3260 size_t cnt_list_sz
= 100;
3266 char **was
, **is
, *pin
;
3267 unsigned int c_cnt
= 0;
3274 * We deal with the case where name already exists in this
3275 * function so the GUI doesn't need to deal with it
3277 name
= gui
->fileselect (_("Save Renumber Annotation File As ..."),
3278 _("Choose a file to record the renumbering to.\n"
3279 "This file may be used to back annotate the\n"
3280 "change to the schematics.\n"),
3281 default_file
, ".eco", "eco",
3291 free (default_file
);
3292 default_file
= NULL
;
3297 default_file
= strdup (name
);
3300 if ((out
= fopen (name
, "r")))
3303 if (!gui
->confirm_dialog (_("File exists! Ok to overwrite?"), 0))
3305 if (free_name
&& name
)
3311 if ((out
= fopen (name
, "w")) == NULL
)
3313 Message (_("Could not open %s\n"), name
);
3314 if (free_name
&& name
)
3319 if (free_name
&& name
)
3322 fprintf (out
, "*COMMENT* PCB Annotation File\n");
3323 fprintf (out
, "*FILEVERSION* 20061031\n");
3326 * Make a first pass through all of the elements and sort them out
3327 * by location on the board. While here we also collect a list of
3330 * We'll actually renumber things in the 2nd pass.
3332 element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementTypePtr
));
3333 locked_element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementTypePtr
));
3334 was
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3335 is
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3336 if (element_list
== NULL
|| locked_element_list
== NULL
|| was
== NULL
3339 fprintf (stderr
, "calloc() failed in %s\n", __FUNCTION__
);
3346 ELEMENT_LOOP (PCB
->Data
);
3348 if (TEST_FLAG (LOCKFLAG
, element
->Name
) || TEST_FLAG (LOCKFLAG
, element
))
3351 * add to the list of locked elements which we won't try to
3352 * renumber and whose reference designators are now reserved.
3355 "*WARN* Element \"%s\" at %$md is locked and will not be renumbered.\n",
3356 UNKNOWN (NAMEONPCB_NAME (element
)), element
->MarkX
, element
->MarkY
);
3357 locked_element_list
[lock_cnt
] = element
;
3363 /* count of devices which will be renumbered */
3366 /* search for correct position in the list */
3368 while (element_list
[i
] && element
->MarkY
> element_list
[i
]->MarkY
)
3372 * We have found the position where we have the first element that
3373 * has the same Y value or a lower Y value. Now move forward if
3374 * needed through the X values
3376 while (element_list
[i
]
3377 && element
->MarkY
== element_list
[i
]->MarkY
3378 && element
->MarkX
> element_list
[i
]->MarkX
)
3381 for (j
= cnt
- 1; j
> i
; j
--)
3383 element_list
[j
] = element_list
[j
- 1];
3385 element_list
[i
] = element
;
3392 * Now that the elements are sorted by board position, we go through
3393 * and renumber them.
3397 * turn off the flag which requires unique names so it doesn't get
3398 * in our way. When we're done with the renumber we will have unique
3401 unique
= TEST_FLAG (UNIQUENAMEFLAG
, PCB
);
3402 CLEAR_FLAG (UNIQUENAMEFLAG
, PCB
);
3404 cnt_list
= (struct _cnt_list
*)calloc (cnt_list_sz
, sizeof (struct _cnt_list
));
3405 for (i
= 0; i
< cnt
; i
++)
3407 /* If there is no refdes, maybe just spit out a warning */
3408 if (NAMEONPCB_NAME (element_list
[i
]))
3410 /* figure out the prefix */
3411 tmps
= strdup (NAMEONPCB_NAME (element_list
[i
]));
3413 while (tmps
[j
] && (tmps
[j
] < '0' || tmps
[j
] > '9')
3418 /* check the counter for this prefix */
3420 cnt_list
[j
].name
&& (strcmp (cnt_list
[j
].name
, tmps
) != 0)
3421 && j
< cnt_list_sz
; j
++);
3423 /* grow the list if needed */
3424 if (j
== cnt_list_sz
)
3427 cnt_list
= (struct _cnt_list
*)realloc (cnt_list
, cnt_list_sz
);
3428 if (cnt_list
== NULL
)
3430 fprintf (stderr
, "realloc failed() in %s\n", __FUNCTION__
);
3433 /* zero out the memory that we added */
3434 for (tmpi
= j
; tmpi
< cnt_list_sz
; tmpi
++)
3436 cnt_list
[tmpi
].name
= NULL
;
3437 cnt_list
[tmpi
].cnt
= 0;
3442 * start a new counter if we don't have a counter for this
3445 if (!cnt_list
[j
].name
)
3447 cnt_list
[j
].name
= strdup (tmps
);
3448 cnt_list
[j
].cnt
= 0;
3452 * check to see if the new refdes is already used by a
3461 /* space for the prefix plus 1 digit plus the '\0' */
3462 sz
= strlen (cnt_list
[j
].name
) + 2;
3464 /* and 1 more per extra digit needed to hold the number */
3465 tmpi
= cnt_list
[j
].cnt
;
3471 tmps
= (char *)malloc (sz
* sizeof (char));
3472 sprintf (tmps
, "%s%d", cnt_list
[j
].name
, cnt_list
[j
].cnt
);
3475 * now compare to the list of reserved (by locked
3478 for (k
= 0; k
< lock_cnt
; k
++)
3481 (UNKNOWN (NAMEONPCB_NAME (locked_element_list
[k
])),
3492 if (strcmp (tmps
, NAMEONPCB_NAME (element_list
[i
])) != 0)
3494 fprintf (out
, "*RENAME* \"%s\" \"%s\"\n",
3495 NAMEONPCB_NAME (element_list
[i
]), tmps
);
3497 /* add this rename to our table of renames so we can update the netlist */
3498 was
[c_cnt
] = strdup (NAMEONPCB_NAME (element_list
[i
]));
3499 is
[c_cnt
] = strdup (tmps
);
3502 AddObjectToChangeNameUndoList (ELEMENT_TYPE
, NULL
, NULL
,
3504 NAMEONPCB_NAME (element_list
3507 ChangeObjectName (ELEMENT_TYPE
, element_list
[i
], NULL
, NULL
,
3511 /* we don't free tmps in this case because it is used */
3518 pcb_fprintf (out
, "*WARN* Element at %$md has no name.\n",
3519 element_list
[i
]->MarkX
, element_list
[i
]->MarkY
);
3526 /* restore the unique flag setting */
3528 SET_FLAG (UNIQUENAMEFLAG
, PCB
);
3533 /* update the netlist */
3534 AddNetlistLibToUndoList (&(PCB
->NetlistLib
));
3536 /* iterate over each net */
3537 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
3540 /* iterate over each pin on the net */
3541 for (j
= 0; j
< PCB
->NetlistLib
.Menu
[i
].EntryN
; j
++)
3544 /* figure out the pin number part from strings like U3-21 */
3545 tmps
= strdup (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3546 for (k
= 0; tmps
[k
] && tmps
[k
] != '-'; k
++);
3550 /* iterate over the list of changed reference designators */
3551 for (k
= 0; k
< c_cnt
; k
++)
3554 * if the pin needs to change, change it and quit
3555 * searching in the list.
3557 if (strcmp (tmps
, was
[k
]) == 0)
3559 free (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3560 PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
=
3561 (char *)malloc ((strlen (is
[k
]) + strlen (pin
) +
3562 2) * sizeof (char));
3563 sprintf (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
,
3564 "%s-%s", is
[k
], pin
);
3572 for (k
= 0; k
< c_cnt
; k
++)
3579 IncrementUndoSerialNumber ();
3580 SetChangedFlag (true);
3583 free (locked_element_list
);
3584 free (element_list
);
3590 /* --------------------------------------------------------------------------- */
3592 static const char ripup_syntax
[] = "RipUp(All|Selected|Element)";
3594 static const char ripup_help
[] =
3595 "Ripup auto-routed tracks, or convert an element to parts.";
3597 /* %start-doc actions RipUp
3602 Removes all lines and vias which were created by the autorouter.
3605 Removes all selected lines and vias which were created by the
3609 Converts the element under the cursor to parts (vias and lines). Note
3610 that this uses the highest numbered paste buffer.
3617 ActionRipUp (int argc
, char **argv
, Coord x
, Coord y
)
3619 char *function
= ARG (0);
3620 bool changed
= false;
3624 switch (GetFunctionID (function
))
3627 ALLLINE_LOOP (PCB
->Data
);
3629 if (TEST_FLAG (AUTOFLAG
, line
) && !TEST_FLAG (LOCKFLAG
, line
))
3631 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3636 ALLARC_LOOP (PCB
->Data
);
3638 if (TEST_FLAG (AUTOFLAG
, arc
) && !TEST_FLAG (LOCKFLAG
, arc
))
3640 RemoveObject (ARC_TYPE
, layer
, arc
, arc
);
3645 VIA_LOOP (PCB
->Data
);
3647 if (TEST_FLAG (AUTOFLAG
, via
) && !TEST_FLAG (LOCKFLAG
, via
))
3649 RemoveObject (VIA_TYPE
, via
, via
, via
);
3657 IncrementUndoSerialNumber ();
3658 SetChangedFlag (true);
3662 VISIBLELINE_LOOP (PCB
->Data
);
3664 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, line
)
3665 && !TEST_FLAG (LOCKFLAG
, line
))
3667 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3673 VIA_LOOP (PCB
->Data
);
3675 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, via
)
3676 && !TEST_FLAG (LOCKFLAG
, via
))
3678 RemoveObject (VIA_TYPE
, via
, via
, via
);
3685 IncrementUndoSerialNumber ();
3686 SetChangedFlag (true);
3691 void *ptr1
, *ptr2
, *ptr3
;
3693 if (SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
3694 &ptr1
, &ptr2
, &ptr3
) != NO_TYPE
)
3696 Note
.Buffer
= Settings
.BufferNumber
;
3697 SetBufferNumber (MAX_BUFFER
- 1);
3698 ClearBuffer (PASTEBUFFER
);
3699 CopyObjectToBuffer (PASTEBUFFER
->Data
, PCB
->Data
,
3700 ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3701 SmashBufferElement (PASTEBUFFER
);
3704 SaveUndoSerialNumber ();
3705 EraseObject (ELEMENT_TYPE
, ptr1
, ptr1
);
3706 MoveObjectToRemoveUndoList (ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3707 RestoreUndoSerialNumber ();
3708 CopyPastebufferToLayout (0, 0);
3709 SetBufferNumber (Note
.Buffer
);
3710 SetChangedFlag (true);
3719 /* --------------------------------------------------------------------------- */
3721 static const char addrats_syntax
[] = "AddRats(AllRats|SelectedRats|Close)";
3723 static const char addrats_help
[] = "Add one or more rat lines to the board.";
3725 /* %start-doc actions AddRats
3730 Create rat lines for all loaded nets that aren't already connected on
3734 Similarly, but only add rat lines for nets connected to selected pins
3738 Selects the shortest unselected rat on the board.
3745 ActionAddRats (int argc
, char **argv
, Coord x
, Coord y
)
3747 char *function
= ARG (0);
3753 if (Settings
.RatWarn
)
3755 switch (GetFunctionID (function
))
3758 if (AddAllRats (false, NULL
))
3759 SetChangedFlag (true);
3761 case F_SelectedRats
:
3763 if (AddAllRats (true, NULL
))
3764 SetChangedFlag (true);
3767 small
= SQUARE (MAX_COORD
);
3769 RAT_LOOP (PCB
->Data
);
3771 if (TEST_FLAG (SELECTEDFLAG
, line
))
3773 len
= SQUARE (line
->Point1
.X
- line
->Point2
.X
) +
3774 SQUARE (line
->Point1
.Y
- line
->Point2
.Y
);
3784 AddObjectToFlagUndoList (RATLINE_TYPE
, shorty
, shorty
, shorty
);
3785 SET_FLAG (SELECTEDFLAG
, shorty
);
3788 CenterDisplay ((shorty
->Point2
.X
+ shorty
->Point1
.X
) / 2,
3789 (shorty
->Point2
.Y
+ shorty
->Point1
.Y
) / 2);
3797 /* --------------------------------------------------------------------------- */
3799 static const char delete_syntax
[] =
3800 "Delete(Object|Selected)\n"
3801 "Delete(AllRats|SelectedRats)";
3803 static const char delete_help
[] = "Delete stuff.";
3805 /* %start-doc actions Delete
3810 ActionDelete (int argc
, char **argv
, Coord x
, Coord y
)
3812 char *function
= ARG (0);
3813 int id
= GetFunctionID (function
);
3815 Note
.X
= Crosshair
.X
;
3816 Note
.Y
= Crosshair
.Y
;
3818 if (id
== -1) /* no arg */
3820 if (RemoveSelected() == false)
3828 SetMode(REMOVE_MODE
);
3836 if (DeleteRats (false))
3837 SetChangedFlag (true);
3839 case F_SelectedRats
:
3840 if (DeleteRats (true))
3841 SetChangedFlag (true);
3848 /* --------------------------------------------------------------------------- */
3850 static const char deleterats_syntax
[] =
3851 "DeleteRats(AllRats|Selected|SelectedRats)";
3853 static const char deleterats_help
[] = "Delete rat lines.";
3855 /* %start-doc actions DeleteRats
3860 ActionDeleteRats (int argc
, char **argv
, Coord x
, Coord y
)
3862 char *function
= ARG (0);
3865 if (Settings
.RatWarn
)
3867 switch (GetFunctionID (function
))
3870 if (DeleteRats (false))
3871 SetChangedFlag (true);
3873 case F_SelectedRats
:
3875 if (DeleteRats (true))
3876 SetChangedFlag (true);
3883 /* --------------------------------------------------------------------------- */
3885 static const char autoplace_syntax
[] = "AutoPlaceSelected()";
3887 static const char autoplace_help
[] = "Auto-place selected components.";
3889 /* %start-doc actions AutoPlaceSelected
3891 Attempts to re-arrange the selected components such that the nets
3892 connecting them are minimized. Note that you cannot undo this.
3897 ActionAutoPlaceSelected (int argc
, char **argv
, Coord x
, Coord y
)
3900 if (gui
->confirm_dialog (_("Auto-placement can NOT be undone.\n"
3901 "Do you want to continue anyway?\n"), 0))
3903 if (AutoPlaceSelected ())
3904 SetChangedFlag (true);
3909 /* --------------------------------------------------------------------------- */
3911 static const char autoroute_syntax
[] = "AutoRoute(AllRats|SelectedRats)";
3913 static const char autoroute_help
[] = "Auto-route some or all rat lines.";
3915 /* %start-doc actions AutoRoute
3920 Attempt to autoroute all rats.
3923 Attempt to autoroute the selected rats.
3927 Before autorouting, it's important to set up a few things. First,
3928 make sure any layers you aren't using are disabled, else the
3929 autorouter may use them. Next, make sure the current line and via
3930 styles are set accordingly. Last, make sure "new lines clear
3931 polygons" is set, in case you eventually want to add a copper pour.
3933 Autorouting takes a while. During this time, the program may not be
3939 ActionAutoRoute (int argc
, char **argv
, Coord x
, Coord y
)
3941 char *function
= ARG (0);
3943 if (function
) /* one parameter */
3945 switch (GetFunctionID (function
))
3948 if (AutoRoute (false))
3949 SetChangedFlag (true);
3951 case F_SelectedRats
:
3953 if (AutoRoute (true))
3954 SetChangedFlag (true);
3961 /* --------------------------------------------------------------------------- */
3963 static const char markcrosshair_syntax
[] =
3965 "MarkCrosshair(Center)";
3967 static const char markcrosshair_help
[] = "Set/Reset the Crosshair mark.";
3969 /* %start-doc actions MarkCrosshair
3971 The ``mark'' is a small X-shaped target on the display which is
3972 treated like a second origin (the normal origin is the upper let
3973 corner of the board). The GUI will display a second set of
3974 coordinates for this mark, which tells you how far you are from it.
3976 If no argument is given, the mark is toggled - disabled if it was
3977 enabled, or enabled at the current cursor position of disabled. If
3978 the @code{Center} argument is given, the mark is moved to the current
3984 ActionMarkCrosshair (int argc
, char **argv
, Coord x
, Coord y
)
3986 char *function
= ARG (0);
3987 if (!function
|| !*function
)
3991 notify_mark_change (false);
3992 Marked
.status
= false;
3993 notify_mark_change (true);
3997 notify_mark_change (false);
3998 Marked
.status
= false;
3999 Marked
.status
= true;
4000 Marked
.X
= Crosshair
.X
;
4001 Marked
.Y
= Crosshair
.Y
;
4002 notify_mark_change (true);
4005 else if (GetFunctionID (function
) == F_Center
)
4007 notify_mark_change (false);
4008 Marked
.status
= true;
4009 Marked
.X
= Crosshair
.X
;
4010 Marked
.Y
= Crosshair
.Y
;
4011 notify_mark_change (true);
4016 /* --------------------------------------------------------------------------- */
4018 static const char changesize_syntax
[] =
4019 "ChangeSize(Object, delta)\n"
4020 "ChangeSize(SelectedObjects|Selected, delta)\n"
4021 "ChangeSize(SelectedLines|SelectedPins|SelectedVias, delta)\n"
4022 "ChangeSize(SelectedPads|SelectedTexts|SelectedNames, delta)\n"
4023 "ChangeSize(SelectedElements, delta)";
4025 static const char changesize_help
[] = "Changes the size of objects.";
4027 /* %start-doc actions ChangeSize
4029 For lines and arcs, this changes the width. For pins and vias, this
4030 changes the overall diameter of the copper annulus. For pads, this
4031 changes the width and, indirectly, the length. For texts and names,
4032 this changes the scaling factor. For elements, this changes the width
4033 of the silk layer lines and arcs for this element.
4038 ActionChangeSize (int argc
, char **argv
, Coord x
, Coord y
)
4040 char *function
= ARG (0);
4041 char *delta
= ARG (1);
4042 char *units
= ARG (2);
4043 bool absolute
; /* indicates if absolute size is given */
4046 if (function
&& delta
)
4048 value
= GetValue (delta
, units
, &absolute
);
4049 switch (GetFunctionID (function
))
4054 void *ptr1
, *ptr2
, *ptr3
;
4057 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
4058 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4059 if (TEST_FLAG (LOCKFLAG
, (PinTypePtr
) ptr2
))
4060 Message (_("Sorry, the object is locked\n"));
4061 if (ChangeObjectSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4062 SetChangedFlag (true);
4066 case F_SelectedVias
:
4067 if (ChangeSelectedSize (VIA_TYPE
, value
, absolute
))
4068 SetChangedFlag (true);
4071 case F_SelectedPins
:
4072 if (ChangeSelectedSize (PIN_TYPE
, value
, absolute
))
4073 SetChangedFlag (true);
4076 case F_SelectedPads
:
4077 if (ChangeSelectedSize (PAD_TYPE
, value
, absolute
))
4078 SetChangedFlag (true);
4081 case F_SelectedArcs
:
4082 if (ChangeSelectedSize (ARC_TYPE
, value
, absolute
))
4083 SetChangedFlag (true);
4086 case F_SelectedLines
:
4087 if (ChangeSelectedSize (LINE_TYPE
, value
, absolute
))
4088 SetChangedFlag (true);
4091 case F_SelectedTexts
:
4092 if (ChangeSelectedSize (TEXT_TYPE
, value
, absolute
))
4093 SetChangedFlag (true);
4096 case F_SelectedNames
:
4097 if (ChangeSelectedSize (ELEMENTNAME_TYPE
, value
, absolute
))
4098 SetChangedFlag (true);
4101 case F_SelectedElements
:
4102 if (ChangeSelectedSize (ELEMENT_TYPE
, value
, absolute
))
4103 SetChangedFlag (true);
4107 case F_SelectedObjects
:
4108 if (ChangeSelectedSize (CHANGESIZE_TYPES
, value
, absolute
))
4109 SetChangedFlag (true);
4116 /* --------------------------------------------------------------------------- */
4118 static const char changedrillsize_syntax
[] =
4119 "ChangeDrillSize(Object, delta)\n"
4120 "ChangeDrillSize(SelectedPins|SelectedVias|Selected|SelectedObjects, delta)";
4122 static const char changedrillsize_help
[] =
4123 "Changes the drilling hole size of objects.";
4125 /* %start-doc actions ChangeDrillSize
4130 ActionChange2ndSize (int argc
, char **argv
, Coord x
, Coord y
)
4132 char *function
= ARG (0);
4133 char *delta
= ARG (1);
4134 char *units
= ARG (2);
4138 if (function
&& delta
)
4140 value
= GetValue (delta
, units
, &absolute
);
4141 switch (GetFunctionID (function
))
4146 void *ptr1
, *ptr2
, *ptr3
;
4148 gui
->get_coords (_("Select an Object"), &x
, &y
);
4150 SearchScreen (x
, y
, CHANGE2NDSIZE_TYPES
,
4151 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4152 if (ChangeObject2ndSize
4153 (type
, ptr1
, ptr2
, ptr3
, value
, absolute
, true))
4154 SetChangedFlag (true);
4158 case F_SelectedVias
:
4159 if (ChangeSelected2ndSize (VIA_TYPE
, value
, absolute
))
4160 SetChangedFlag (true);
4163 case F_SelectedPins
:
4164 if (ChangeSelected2ndSize (PIN_TYPE
, value
, absolute
))
4165 SetChangedFlag (true);
4168 case F_SelectedObjects
:
4169 if (ChangeSelected2ndSize (PIN_TYPES
, value
, absolute
))
4170 SetChangedFlag (true);
4177 /* --------------------------------------------------------------------------- */
4179 static const char changeclearsize_syntax
[] =
4180 "ChangeClearSize(Object, delta)\n"
4181 "ChangeClearSize(SelectedPins|SelectedPads|SelectedVias, delta)\n"
4182 "ChangeClearSize(SelectedLines|SelectedArcs, delta\n"
4183 "ChangeClearSize(Selected|SelectedObjects, delta)";
4185 static const char changeclearsize_help
[] =
4186 "Changes the clearance size of objects.";
4188 /* %start-doc actions ChangeClearSize
4190 If the solder mask is currently showing, this action changes the
4191 solder mask clearance. If the mask is not showing, this action
4192 changes the polygon clearance.
4197 ActionChangeClearSize (int argc
, char **argv
, Coord x
, Coord y
)
4199 char *function
= ARG (0);
4200 char *delta
= ARG (1);
4201 char *units
= ARG (2);
4205 if (function
&& delta
)
4207 value
= 2 * GetValue (delta
, units
, &absolute
);
4208 switch (GetFunctionID (function
))
4213 void *ptr1
, *ptr2
, *ptr3
;
4215 gui
->get_coords (_("Select an Object"), &x
, &y
);
4218 CHANGECLEARSIZE_TYPES
, &ptr1
, &ptr2
,
4220 if (ChangeObjectClearSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4221 SetChangedFlag (true);
4224 case F_SelectedVias
:
4225 if (ChangeSelectedClearSize (VIA_TYPE
, value
, absolute
))
4226 SetChangedFlag (true);
4228 case F_SelectedPads
:
4229 if (ChangeSelectedClearSize (PAD_TYPE
, value
, absolute
))
4230 SetChangedFlag (true);
4232 case F_SelectedPins
:
4233 if (ChangeSelectedClearSize (PIN_TYPE
, value
, absolute
))
4234 SetChangedFlag (true);
4236 case F_SelectedLines
:
4237 if (ChangeSelectedClearSize (LINE_TYPE
, value
, absolute
))
4238 SetChangedFlag (true);
4240 case F_SelectedArcs
:
4241 if (ChangeSelectedClearSize (ARC_TYPE
, value
, absolute
))
4242 SetChangedFlag (true);
4245 case F_SelectedObjects
:
4246 if (ChangeSelectedClearSize (CHANGECLEARSIZE_TYPES
, value
, absolute
))
4247 SetChangedFlag (true);
4254 /* --------------------------------------------------------------------------- */
4256 static const char minmaskgap_syntax
[] =
4257 "MinMaskGap(delta)\n"
4258 "MinMaskGap(Selected, delta)";
4260 static const char minmaskgap_help
[] =
4261 "Ensures the mask is a minimum distance from pins and pads.";
4263 /* %start-doc actions MinMaskGap
4265 Checks all specified pins and/or pads, and increases the mask if
4266 needed to ensure a minimum distance between the pin or pad edge and
4272 ActionMinMaskGap (int argc
, char **argv
, Coord x
, Coord y
)
4274 char *function
= ARG (0);
4275 char *delta
= ARG (1);
4276 char *units
= ARG (2);
4283 if (strcasecmp (function
, "Selected") == 0)
4284 flags
= SELECTEDFLAG
;
4291 value
= 2 * GetValue (delta
, units
, &absolute
);
4293 SaveUndoSerialNumber ();
4294 ELEMENT_LOOP (PCB
->Data
);
4298 if (!TEST_FLAGS (flags
, pin
))
4300 if (pin
->Mask
< pin
->Thickness
+ value
)
4302 ChangeObjectMaskSize (PIN_TYPE
, element
, pin
, 0,
4303 pin
->Thickness
+ value
, 1);
4304 RestoreUndoSerialNumber ();
4310 if (!TEST_FLAGS (flags
, pad
))
4312 if (pad
->Mask
< pad
->Thickness
+ value
)
4314 ChangeObjectMaskSize (PAD_TYPE
, element
, pad
, 0,
4315 pad
->Thickness
+ value
, 1);
4316 RestoreUndoSerialNumber ();
4322 VIA_LOOP (PCB
->Data
);
4324 if (!TEST_FLAGS (flags
, via
))
4326 if (via
->Mask
&& via
->Mask
< via
->Thickness
+ value
)
4328 ChangeObjectMaskSize (VIA_TYPE
, via
, 0, 0, via
->Thickness
+ value
, 1);
4329 RestoreUndoSerialNumber ();
4333 RestoreUndoSerialNumber ();
4334 IncrementUndoSerialNumber ();
4338 /* --------------------------------------------------------------------------- */
4340 static const char mincleargap_syntax
[] =
4341 "MinClearGap(delta)\n"
4342 "MinClearGap(Selected, delta)";
4344 static const char mincleargap_help
[] =
4345 "Ensures that polygons are a minimum distance from objects.";
4347 /* %start-doc actions MinClearGap
4349 Checks all specified objects, and increases the polygon clearance if
4350 needed to ensure a minimum distance between their edges and the
4356 ActionMinClearGap (int argc
, char **argv
, Coord x
, Coord y
)
4358 char *function
= ARG (0);
4359 char *delta
= ARG (1);
4360 char *units
= ARG (2);
4367 if (strcasecmp (function
, "Selected") == 0)
4368 flags
= SELECTEDFLAG
;
4375 value
= 2 * GetValue (delta
, units
, &absolute
);
4377 SaveUndoSerialNumber ();
4378 ELEMENT_LOOP (PCB
->Data
);
4382 if (!TEST_FLAGS (flags
, pin
))
4384 if (pin
->Clearance
< value
)
4386 ChangeObjectClearSize (PIN_TYPE
, element
, pin
, 0,
4388 RestoreUndoSerialNumber ();
4394 if (!TEST_FLAGS (flags
, pad
))
4396 if (pad
->Clearance
< value
)
4398 ChangeObjectClearSize (PAD_TYPE
, element
, pad
, 0,
4400 RestoreUndoSerialNumber ();
4406 VIA_LOOP (PCB
->Data
);
4408 if (!TEST_FLAGS (flags
, via
))
4410 if (via
->Clearance
< value
)
4412 ChangeObjectClearSize (VIA_TYPE
, via
, 0, 0, value
, 1);
4413 RestoreUndoSerialNumber ();
4417 ALLLINE_LOOP (PCB
->Data
);
4419 if (!TEST_FLAGS (flags
, line
))
4421 if (line
->Clearance
< value
)
4423 ChangeObjectClearSize (LINE_TYPE
, layer
, line
, 0, value
, 1);
4424 RestoreUndoSerialNumber ();
4428 ALLARC_LOOP (PCB
->Data
);
4430 if (!TEST_FLAGS (flags
, arc
))
4432 if (arc
->Clearance
< value
)
4434 ChangeObjectClearSize (ARC_TYPE
, layer
, arc
, 0, value
, 1);
4435 RestoreUndoSerialNumber ();
4439 RestoreUndoSerialNumber ();
4440 IncrementUndoSerialNumber ();
4444 /* --------------------------------------------------------------------------- */
4446 static const char changepinname_syntax
[] =
4447 "ChangePinName(ElementName,PinNumber,PinName)";
4449 static const char changepinname_help
[] =
4450 "Sets the name of a specific pin on a specific element.";
4452 /* %start-doc actions ChangePinName
4454 This can be especially useful for annotating pin names from a
4455 schematic to the layout without requiring knowledge of the pcb file
4459 ChangePinName(U3, 7, VCC)
4465 ActionChangePinName (int argc
, char **argv
, Coord x
, Coord y
)
4468 char *refdes
, *pinnum
, *pinname
;
4472 AFAIL (changepinname
);
4479 ELEMENT_LOOP (PCB
->Data
);
4481 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
4485 if (NSTRCMP (pinnum
, pin
->Number
) == 0)
4487 AddObjectToChangeNameUndoList (PIN_TYPE
, NULL
, NULL
,
4490 * Note: we can't free() pin->Name first because
4491 * it is used in the undo list
4493 pin
->Name
= strdup (pinname
);
4494 SetChangedFlag (true);
4502 if (NSTRCMP (pinnum
, pad
->Number
) == 0)
4504 AddObjectToChangeNameUndoList (PAD_TYPE
, NULL
, NULL
,
4507 * Note: we can't free() pad->Name first because
4508 * it is used in the undo list
4510 pad
->Name
= strdup (pinname
);
4511 SetChangedFlag (true);
4520 * done with our action so increment the undo # if we actually
4526 defer_needs_update
= 1;
4529 IncrementUndoSerialNumber ();
4530 gui
->invalidate_all ();
4537 /* --------------------------------------------------------------------------- */
4539 static const char changename_syntax
[] =
4540 "ChangeName(Object)\n"
4541 "ChangeName(Layout|Layer)";
4543 static const char changename_help
[] = "Sets the name of objects.";
4545 /* %start-doc actions ChangeName
4550 Changes the name of the element under the cursor.
4553 Changes the name of the layout. This is printed on the fab drawings.
4556 Changes the name of the currently active layer.
4563 ActionChangeName (int argc
, char **argv
, Coord x
, Coord y
)
4565 char *function
= ARG (0);
4570 switch (GetFunctionID (function
))
4572 /* change the name of an object */
4576 void *ptr1
, *ptr2
, *ptr3
;
4578 gui
->get_coords (_("Select an Object"), &x
, &y
);
4580 SearchScreen (x
, y
, CHANGENAME_TYPES
,
4581 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4583 SaveUndoSerialNumber ();
4584 if (QueryInputAndChangeObjectName (type
, ptr1
, ptr2
, ptr3
))
4586 SetChangedFlag (true);
4587 if (type
== ELEMENT_TYPE
)
4589 RubberbandTypePtr ptr
;
4592 RestoreUndoSerialNumber ();
4593 Crosshair
.AttachedObject
.RubberbandN
= 0;
4594 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
4595 ptr
= Crosshair
.AttachedObject
.Rubberband
;
4596 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
;
4600 EraseRat ((RatTypePtr
) ptr
->Line
);
4601 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
4602 ptr
->Line
, ptr
->Line
,
4605 IncrementUndoSerialNumber ();
4613 /* change the layout's name */
4616 gui
->prompt_for (_("Enter the layout name:"), EMPTY (PCB
->Name
));
4617 /* NB: ChangeLayoutName takes ownership of the passed memory */
4618 if (name
&& ChangeLayoutName (name
))
4619 SetChangedFlag (true);
4622 /* change the name of the active layer */
4624 name
= gui
->prompt_for (_("Enter the layer name:"),
4625 EMPTY (CURRENT
->Name
));
4626 /* NB: ChangeLayerName takes ownership of the passed memory */
4627 if (name
&& ChangeLayerName (CURRENT
, name
))
4628 SetChangedFlag (true);
4636 /* --------------------------------------------------------------------------- */
4638 static const char morphpolygon_syntax
[] = "MorphPolygon(Object|Selected)";
4640 static const char morphpolygon_help
[] =
4641 "Converts dead polygon islands into separate polygons.";
4643 /* %start-doc actions MorphPolygon
4645 If a polygon is divided into unconnected "islands", you can use
4646 this command to convert the otherwise disappeared islands into
4647 separate polygons. Be sure the cursor is over a portion of the
4648 polygon that remains visible. Very small islands that may flake
4649 off are automatically deleted.
4654 ActionMorphPolygon (int argc
, char **argv
, Coord x
, Coord y
)
4656 char *function
= ARG (0);
4659 switch (GetFunctionID (function
))
4664 void *ptr1
, *ptr2
, *ptr3
;
4666 gui
->get_coords (_("Select an Object"), &x
, &y
);
4667 if ((type
= SearchScreen (x
, y
, POLYGON_TYPE
,
4668 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4670 MorphPolygon ((LayerType
*) ptr1
, (PolygonType
*) ptr3
);
4672 IncrementUndoSerialNumber ();
4677 case F_SelectedObjects
:
4678 ALLPOLYGON_LOOP (PCB
->Data
);
4680 if (TEST_FLAG (SELECTEDFLAG
, polygon
))
4681 MorphPolygon (layer
, polygon
);
4685 IncrementUndoSerialNumber ();
4692 /* --------------------------------------------------------------------------- */
4694 static const char togglehidename_syntax
[] =
4695 "ToggleHideName(Object|SelectedElements)";
4697 static const char togglehidename_help
[] =
4698 "Toggles the visibility of element names.";
4700 /* %start-doc actions ToggleHideName
4702 If names are hidden you won't see them on the screen and they will not
4703 appear on the silk layer when you print the layout.
4708 ActionToggleHideName (int argc
, char **argv
, Coord x
, Coord y
)
4710 char *function
= ARG (0);
4711 if (function
&& PCB
->ElementOn
)
4713 switch (GetFunctionID (function
))
4718 void *ptr1
, *ptr2
, *ptr3
;
4720 gui
->get_coords (_("Select an Object"), &x
, &y
);
4721 if ((type
= SearchScreen (x
, y
, ELEMENT_TYPE
,
4722 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4724 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr3
);
4725 EraseElementName ((ElementTypePtr
) ptr2
);
4726 TOGGLE_FLAG (HIDENAMEFLAG
, (ElementTypePtr
) ptr2
);
4727 DrawElementName ((ElementTypePtr
) ptr2
);
4729 IncrementUndoSerialNumber ();
4733 case F_SelectedElements
:
4736 bool changed
= false;
4737 ELEMENT_LOOP (PCB
->Data
);
4739 if ((TEST_FLAG (SELECTEDFLAG
, element
) ||
4740 TEST_FLAG (SELECTEDFLAG
,
4741 &NAMEONPCB_TEXT (element
)))
4742 && (FRONT (element
) || PCB
->InvisibleObjectsOn
))
4744 AddObjectToFlagUndoList (ELEMENT_TYPE
, element
,
4746 EraseElementName (element
);
4747 TOGGLE_FLAG (HIDENAMEFLAG
, element
);
4748 DrawElementName (element
);
4756 IncrementUndoSerialNumber ();
4764 /* --------------------------------------------------------------------------- */
4766 static const char changejoin_syntax
[] =
4767 "ChangeJoin(ToggleObject|SelectedLines|SelectedArcs|Selected)";
4769 static const char changejoin_help
[] =
4770 "Changes the join (clearance through polygons) of objects.";
4772 /* %start-doc actions ChangeJoin
4774 The join flag determines whether a line or arc, drawn to intersect a
4775 polygon, electrically connects to the polygon or not. When joined,
4776 the line/arc is simply drawn over the polygon, making an electrical
4777 connection. When not joined, a gap is drawn between the line and the
4778 polygon, insulating them from each other.
4783 ActionChangeJoin (int argc
, char **argv
, Coord x
, Coord y
)
4785 char *function
= ARG (0);
4788 switch (GetFunctionID (function
))
4790 case F_ToggleObject
:
4794 void *ptr1
, *ptr2
, *ptr3
;
4796 gui
->get_coords (_("Select an Object"), &x
, &y
);
4798 SearchScreen (x
, y
, CHANGEJOIN_TYPES
,
4799 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4800 if (ChangeObjectJoin (type
, ptr1
, ptr2
, ptr3
))
4801 SetChangedFlag (true);
4805 case F_SelectedLines
:
4806 if (ChangeSelectedJoin (LINE_TYPE
))
4807 SetChangedFlag (true);
4810 case F_SelectedArcs
:
4811 if (ChangeSelectedJoin (ARC_TYPE
))
4812 SetChangedFlag (true);
4816 case F_SelectedObjects
:
4817 if (ChangeSelectedJoin (CHANGEJOIN_TYPES
))
4818 SetChangedFlag (true);
4825 /* --------------------------------------------------------------------------- */
4827 static const char changesquare_syntax
[] =
4828 "ChangeSquare(ToggleObject)\n"
4829 "ChangeSquare(SelectedElements|SelectedPins)\n"
4830 "ChangeSquare(Selected|SelectedObjects)";
4832 static const char changesquare_help
[] =
4833 "Changes the square flag of pins and pads.";
4835 /* %start-doc actions ChangeSquare
4837 Note that @code{Pins} means both pins and pads.
4844 ActionChangeSquare (int argc
, char **argv
, Coord x
, Coord y
)
4846 char *function
= ARG (0);
4849 switch (GetFunctionID (function
))
4851 case F_ToggleObject
:
4855 void *ptr1
, *ptr2
, *ptr3
;
4857 gui
->get_coords (_("Select an Object"), &x
, &y
);
4859 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4860 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4861 if (ChangeObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4862 SetChangedFlag (true);
4866 case F_SelectedElements
:
4867 if (ChangeSelectedSquare (ELEMENT_TYPE
))
4868 SetChangedFlag (true);
4871 case F_SelectedPins
:
4872 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4873 SetChangedFlag (true);
4877 case F_SelectedObjects
:
4878 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4879 SetChangedFlag (true);
4886 /* --------------------------------------------------------------------------- */
4888 static const char setsquare_syntax
[] =
4889 "SetSquare(ToggleObject|SelectedElements|SelectedPins)";
4891 static const char setsquare_help
[] = "sets the square-flag of objects.";
4893 /* %start-doc actions SetSquare
4895 Note that @code{Pins} means pins and pads.
4902 ActionSetSquare (int argc
, char **argv
, Coord x
, Coord y
)
4904 char *function
= ARG (0);
4905 if (function
&& *function
)
4907 switch (GetFunctionID (function
))
4909 case F_ToggleObject
:
4913 void *ptr1
, *ptr2
, *ptr3
;
4915 gui
->get_coords (_("Select an Object"), &x
, &y
);
4917 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4918 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4919 if (SetObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4920 SetChangedFlag (true);
4924 case F_SelectedElements
:
4925 if (SetSelectedSquare (ELEMENT_TYPE
))
4926 SetChangedFlag (true);
4929 case F_SelectedPins
:
4930 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4931 SetChangedFlag (true);
4935 case F_SelectedObjects
:
4936 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4937 SetChangedFlag (true);
4944 /* --------------------------------------------------------------------------- */
4946 static const char clearsquare_syntax
[] =
4947 "ClearSquare(ToggleObject|SelectedElements|SelectedPins)";
4949 static const char clearsquare_help
[] =
4950 "Clears the square-flag of pins and pads.";
4952 /* %start-doc actions ClearSquare
4954 Note that @code{Pins} means pins and pads.
4961 ActionClearSquare (int argc
, char **argv
, Coord x
, Coord y
)
4963 char *function
= ARG (0);
4964 if (function
&& *function
)
4966 switch (GetFunctionID (function
))
4968 case F_ToggleObject
:
4972 void *ptr1
, *ptr2
, *ptr3
;
4974 gui
->get_coords (_("Select an Object"), &x
, &y
);
4976 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4977 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4978 if (ClrObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4979 SetChangedFlag (true);
4983 case F_SelectedElements
:
4984 if (ClrSelectedSquare (ELEMENT_TYPE
))
4985 SetChangedFlag (true);
4988 case F_SelectedPins
:
4989 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4990 SetChangedFlag (true);
4994 case F_SelectedObjects
:
4995 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4996 SetChangedFlag (true);
5003 /* --------------------------------------------------------------------------- */
5005 static const char changeoctagon_syntax
[] =
5006 "ChangeOctagon(Object|ToggleObject|SelectedObjects|Selected)\n"
5007 "ChangeOctagon(SelectedElements|SelectedPins|SelectedVias)";
5009 static const char changeoctagon_help
[] =
5010 "Changes the octagon-flag of pins and vias.";
5012 /* %start-doc actions ChangeOctagon
5019 ActionChangeOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5021 char *function
= ARG (0);
5024 switch (GetFunctionID (function
))
5026 case F_ToggleObject
:
5030 void *ptr1
, *ptr2
, *ptr3
;
5032 gui
->get_coords (_("Select an Object"), &x
, &y
);
5034 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5035 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5036 if (ChangeObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5037 SetChangedFlag (true);
5041 case F_SelectedElements
:
5042 if (ChangeSelectedOctagon (ELEMENT_TYPE
))
5043 SetChangedFlag (true);
5046 case F_SelectedPins
:
5047 if (ChangeSelectedOctagon (PIN_TYPE
))
5048 SetChangedFlag (true);
5051 case F_SelectedVias
:
5052 if (ChangeSelectedOctagon (VIA_TYPE
))
5053 SetChangedFlag (true);
5057 case F_SelectedObjects
:
5058 if (ChangeSelectedOctagon (PIN_TYPES
))
5059 SetChangedFlag (true);
5066 /* --------------------------------------------------------------------------- */
5068 static const char setoctagon_syntax
[] =
5069 "SetOctagon(Object|ToggleObject|SelectedElements|Selected)";
5071 static const char setoctagon_help
[] = "Sets the octagon-flag of objects.";
5073 /* %start-doc actions SetOctagon
5080 ActionSetOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5082 char *function
= ARG (0);
5085 switch (GetFunctionID (function
))
5087 case F_ToggleObject
:
5091 void *ptr1
, *ptr2
, *ptr3
;
5093 gui
->get_coords (_("Select an Object"), &x
, &y
);
5095 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5096 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5097 if (SetObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5098 SetChangedFlag (true);
5102 case F_SelectedElements
:
5103 if (SetSelectedOctagon (ELEMENT_TYPE
))
5104 SetChangedFlag (true);
5107 case F_SelectedPins
:
5108 if (SetSelectedOctagon (PIN_TYPE
))
5109 SetChangedFlag (true);
5112 case F_SelectedVias
:
5113 if (SetSelectedOctagon (VIA_TYPE
))
5114 SetChangedFlag (true);
5118 case F_SelectedObjects
:
5119 if (SetSelectedOctagon (PIN_TYPES
))
5120 SetChangedFlag (true);
5127 /* --------------------------------------------------------------------------- */
5129 static const char clearoctagon_syntax
[] =
5130 "ClearOctagon(ToggleObject|Object|SelectedObjects|Selected)\n"
5131 "ClearOctagon(SelectedElements|SelectedPins|SelectedVias)";
5133 static const char clearoctagon_help
[] =
5134 "Clears the octagon-flag of pins and vias.";
5136 /* %start-doc actions ClearOctagon
5143 ActionClearOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5145 char *function
= ARG (0);
5148 switch (GetFunctionID (function
))
5150 case F_ToggleObject
:
5154 void *ptr1
, *ptr2
, *ptr3
;
5156 gui
->get_coords (_("Select an Object"), &x
, &y
);
5158 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGEOCTAGON_TYPES
,
5159 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5160 if (ClrObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5161 SetChangedFlag (true);
5165 case F_SelectedElements
:
5166 if (ClrSelectedOctagon (ELEMENT_TYPE
))
5167 SetChangedFlag (true);
5170 case F_SelectedPins
:
5171 if (ClrSelectedOctagon (PIN_TYPE
))
5172 SetChangedFlag (true);
5175 case F_SelectedVias
:
5176 if (ClrSelectedOctagon (VIA_TYPE
))
5177 SetChangedFlag (true);
5181 case F_SelectedObjects
:
5182 if (ClrSelectedOctagon (PIN_TYPES
))
5183 SetChangedFlag (true);
5190 /* --------------------------------------------------------------------------- */
5192 static const char changehold_syntax
[] =
5193 "ChangeHole(ToggleObject|Object|SelectedVias|Selected)";
5195 static const char changehold_help
[] = "Changes the hole flag of objects.";
5197 /* %start-doc actions ChangeHole
5199 The "hole flag" of a via determines whether the via is a
5200 plated-through hole (not set), or an unplated hole (set).
5205 ActionChangeHole (int argc
, char **argv
, Coord x
, Coord y
)
5207 char *function
= ARG (0);
5210 switch (GetFunctionID (function
))
5212 case F_ToggleObject
:
5216 void *ptr1
, *ptr2
, *ptr3
;
5218 gui
->get_coords (_("Select an Object"), &x
, &y
);
5219 if ((type
= SearchScreen (x
, y
, VIA_TYPE
,
5220 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5221 && ChangeHole ((PinTypePtr
) ptr3
))
5222 IncrementUndoSerialNumber ();
5226 case F_SelectedVias
:
5228 if (ChangeSelectedHole ())
5229 SetChangedFlag (true);
5236 /* --------------------------------------------------------------------------- */
5238 static const char changepaste_syntax
[] =
5239 "ChangePaste(ToggleObject|Object|SelectedPads|Selected)";
5241 static const char changepaste_help
[] = "Changes the no paste flag of objects.";
5243 /* %start-doc actions ChangePaste
5245 The "no paste flag" of a pad determines whether the solderpaste
5246 stencil will have an opening for the pad (no set) or if there wil be
5247 no solderpaste on the pad (set). This is used for things such as
5253 ActionChangePaste (int argc
, char **argv
, Coord x
, Coord y
)
5255 char *function
= ARG (0);
5258 switch (GetFunctionID (function
))
5260 case F_ToggleObject
:
5264 void *ptr1
, *ptr2
, *ptr3
;
5266 gui
->get_coords (_("Select an Object"), &x
, &y
);
5267 if ((type
= SearchScreen (x
, y
, PAD_TYPE
,
5268 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5269 && ChangePaste ((PadTypePtr
) ptr3
))
5270 IncrementUndoSerialNumber ();
5274 case F_SelectedPads
:
5276 if (ChangeSelectedPaste ())
5277 SetChangedFlag (true);
5284 /* --------------------------------------------------------------------------- */
5286 static const char select_syntax
[] =
5287 "Select(Object|ToggleObject)\n"
5288 "Select(All|Block|Connection)\n"
5289 "Select(ElementByName|ObjectByName|PadByName|PinByName)\n"
5290 "Select(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5291 "Select(TextByName|ViaByName|NetByName)\n"
5292 "Select(TextByName|ViaByName|NetByName, Name)\n"
5295 static const char select_help
[] = "Toggles or sets the selection.";
5297 /* %start-doc actions Select
5309 These all rely on having a regular expression parser built into
5310 @code{pcb}. If the name is not specified then the user is prompted
5311 for a pattern, and all objects that match the pattern and are of the
5312 type specified are selected.
5316 Selects the object under the cursor.
5319 Selects all objects in a rectangle indicated by the cursor.
5322 Selects all objects on the board.
5325 Selects all connections with the ``found'' flag set.
5328 Converts the selected objects to an element. This uses the highest
5329 numbered paste buffer.
5336 ActionSelect (int argc
, char **argv
, Coord x
, Coord y
)
5338 char *function
= ARG (0);
5341 switch (GetFunctionID (function
))
5343 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5345 /* select objects by their names */
5346 case F_ElementByName
:
5347 type
= ELEMENT_TYPE
;
5349 case F_ObjectByName
:
5370 char *pattern
= ARG (1);
5374 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5376 if (SelectObjectByName (type
, pattern
, true))
5377 SetChangedFlag (true);
5378 if (ARG (1) == NULL
)
5383 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5385 /* select a single object */
5386 case F_ToggleObject
:
5388 if (SelectObject ())
5389 SetChangedFlag (true);
5392 /* all objects in block */
5397 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5398 Crosshair
.AttachedBox
.Point2
.X
);
5399 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5400 Crosshair
.AttachedBox
.Point2
.Y
);
5401 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5402 Crosshair
.AttachedBox
.Point2
.X
);
5403 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5404 Crosshair
.AttachedBox
.Point2
.Y
);
5405 notify_crosshair_change (false);
5407 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5408 SelectBlock (&box
, true))
5410 SetChangedFlag (true);
5411 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5413 notify_crosshair_change (true);
5417 /* select all visible objects */
5422 box
.X1
= -MAX_COORD
;
5423 box
.Y1
= -MAX_COORD
;
5426 if (SelectBlock (&box
, true))
5427 SetChangedFlag (true);
5431 /* all found connections */
5433 if (SelectConnection (true))
5436 IncrementUndoSerialNumber ();
5437 SetChangedFlag (true);
5444 Note
.Buffer
= Settings
.BufferNumber
;
5445 SetBufferNumber (MAX_BUFFER
- 1);
5446 ClearBuffer (PASTEBUFFER
);
5447 gui
->get_coords (_("Select the Element's Mark Location"), &x
, &y
);
5448 x
= GridFit (x
, PCB
->Grid
, PCB
->GridOffsetX
);
5449 y
= GridFit (y
, PCB
->Grid
, PCB
->GridOffsetY
);
5450 AddSelectedToBuffer (PASTEBUFFER
, x
, y
, true);
5451 SaveUndoSerialNumber ();
5453 ConvertBufferToElement (PASTEBUFFER
);
5454 RestoreUndoSerialNumber ();
5455 CopyPastebufferToLayout (x
, y
);
5456 SetBufferNumber (Note
.Buffer
);
5468 /* FLAG(have_regex,FlagHaveRegex,0) */
5470 FlagHaveRegex (int parm
)
5472 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5479 /* --------------------------------------------------------------------------- */
5481 static const char unselect_syntax
[] =
5482 "Unselect(All|Block|Connection)\n"
5483 "Unselect(ElementByName|ObjectByName|PadByName|PinByName)\n"
5484 "Unselect(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5485 "Unselect(TextByName|ViaByName)\n"
5486 "Unselect(TextByName|ViaByName, Name)\n";
5488 static const char unselect_help
[] =
5489 "Unselects the object at the pointer location or the specified objects.";
5491 /* %start-doc actions Unselect
5496 Unselect all objects.
5499 Unselect all objects in a rectangle given by the cursor.
5502 Unselect all connections with the ``found'' flag set.
5511 These all rely on having a regular expression parser built into
5512 @code{pcb}. If the name is not specified then the user is prompted
5513 for a pattern, and all objects that match the pattern and are of the
5514 type specified are unselected.
5522 ActionUnselect (int argc
, char **argv
, Coord x
, Coord y
)
5524 char *function
= ARG (0);
5527 switch (GetFunctionID (function
))
5529 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5531 /* select objects by their names */
5532 case F_ElementByName
:
5533 type
= ELEMENT_TYPE
;
5535 case F_ObjectByName
:
5556 char *pattern
= ARG (1);
5560 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5562 if (SelectObjectByName (type
, pattern
, false))
5563 SetChangedFlag (true);
5564 if (ARG (1) == NULL
)
5569 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5571 /* all objects in block */
5576 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5577 Crosshair
.AttachedBox
.Point2
.X
);
5578 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5579 Crosshair
.AttachedBox
.Point2
.Y
);
5580 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5581 Crosshair
.AttachedBox
.Point2
.X
);
5582 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5583 Crosshair
.AttachedBox
.Point2
.Y
);
5584 notify_crosshair_change (false);
5586 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5587 SelectBlock (&box
, false))
5589 SetChangedFlag (true);
5590 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5592 notify_crosshair_change (true);
5596 /* unselect all visible objects */
5601 box
.X1
= -MAX_COORD
;
5602 box
.Y1
= -MAX_COORD
;
5605 if (SelectBlock (&box
, false))
5606 SetChangedFlag (true);
5610 /* all found connections */
5612 if (SelectConnection (false))
5615 IncrementUndoSerialNumber ();
5616 SetChangedFlag (true);
5629 /* --------------------------------------------------------------------------- */
5631 static const char saveto_syntax
[] =
5632 "SaveTo(Layout|LayoutAs,filename)\n"
5633 "SaveTo(AllConnections|AllUnusedPins|ElementConnections,filename)\n"
5634 "SaveTo(PasteBuffer,filename)";
5636 static const char saveto_help
[] = "Saves data to a file.";
5638 /* %start-doc actions SaveTo
5643 Saves the current layout.
5646 Saves the current layout, and remembers the filename used.
5648 @item AllConnections
5649 Save all connections to a file.
5652 List all unused pins to a file.
5654 @item ElementConnections
5655 Save connections to the element at the cursor to a file.
5658 Save the content of the active Buffer to a file. This is the graphical way to create a footprint.
5665 ActionSaveTo (int argc
, char **argv
, Coord x
, Coord y
)
5673 if (strcasecmp (function
, "Layout") == 0)
5675 if (SavePCB (PCB
->Filename
) == 0)
5676 SetChangedFlag (false);
5683 if (strcasecmp (function
, "LayoutAs") == 0)
5685 if (SavePCB (name
) == 0)
5687 SetChangedFlag (false);
5688 free (PCB
->Filename
);
5689 PCB
->Filename
= strdup (name
);
5690 if (gui
->notify_filename_changed
!= NULL
)
5691 gui
->notify_filename_changed ();
5696 if (strcasecmp (function
, "AllConnections") == 0)
5700 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5702 LookupConnectionsToAllElements (fp
);
5704 SetChangedFlag (true);
5709 if (strcasecmp (function
, "AllUnusedPins") == 0)
5713 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5715 LookupUnusedPins (fp
);
5717 SetChangedFlag (true);
5722 if (strcasecmp (function
, "ElementConnections") == 0)
5724 ElementTypePtr element
;
5729 if ((SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
5730 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
5732 element
= (ElementTypePtr
) ptrtmp
;
5734 CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5736 LookupElementConnections (element
, fp
);
5738 SetChangedFlag (true);
5744 if (strcasecmp (function
, "PasteBuffer") == 0)
5746 return SaveBufferElements (name
);
5752 /* --------------------------------------------------------------------------- */
5754 static const char savesettings_syntax
[] =
5756 "SaveSettings(local)";
5758 static const char savesettings_help
[] = "Saves settings.";
5760 /* %start-doc actions SaveSettings
5762 If you pass no arguments, the settings are stored in
5763 @code{$HOME/.pcb/settings}. If you pass the word @code{local} they're
5764 saved in @code{./pcb.settings}.
5769 ActionSaveSettings (int argc
, char **argv
, Coord x
, Coord y
)
5771 int locally
= argc
> 0 ? (strncasecmp (argv
[0], "local", 5) == 0) : 0;
5772 hid_save_settings (locally
);
5776 /* --------------------------------------------------------------------------- */
5778 static const char loadfrom_syntax
[] =
5779 "LoadFrom(Layout|LayoutToBuffer|ElementToBuffer|Netlist|Revert,filename)";
5781 static const char loadfrom_help
[] = "Load layout data from a file.";
5783 /* %start-doc actions LoadFrom
5785 This action assumes you know what the filename is. The various GUIs
5786 should have a similar @code{Load} action where the filename is
5787 optional, and will provide their own file selection mechanism to let
5788 you choose the file name.
5793 Loads an entire PCB layout, replacing the current one.
5795 @item LayoutToBuffer
5796 Loads an entire PCB layout to the paste buffer.
5798 @item ElementToBuffer
5799 Loads the given element file into the paste buffer. Element files
5800 contain only a single @code{Element} definition, such as the
5801 ``newlib'' library uses.
5804 Loads a new netlist, replacing any current netlist.
5807 Re-loads the current layout from its disk file, reverting any changes
5815 ActionLoadFrom (int argc
, char **argv
, Coord x
, Coord y
)
5826 if (strcasecmp (function
, "ElementToBuffer") == 0)
5828 notify_crosshair_change (false);
5829 if (LoadElementToBuffer (PASTEBUFFER
, name
, true))
5830 SetMode (PASTEBUFFER_MODE
);
5831 notify_crosshair_change (true);
5834 else if (strcasecmp (function
, "LayoutToBuffer") == 0)
5836 notify_crosshair_change (false);
5837 if (LoadLayoutToBuffer (PASTEBUFFER
, name
))
5838 SetMode (PASTEBUFFER_MODE
);
5839 notify_crosshair_change (true);
5842 else if (strcasecmp (function
, "Layout") == 0)
5844 if (!PCB
->Changed
||
5845 gui
->confirm_dialog (_("OK to override layout data?"), 0))
5849 else if (strcasecmp (function
, "Netlist") == 0)
5851 if (PCB
->Netlistname
)
5852 free (PCB
->Netlistname
);
5853 PCB
->Netlistname
= StripWhiteSpaceAndDup (name
);
5854 FreeLibraryMemory (&PCB
->NetlistLib
);
5855 if (!ImportNetlist (PCB
->Netlistname
))
5858 else if (strcasecmp (function
, "Revert") == 0 && PCB
->Filename
5860 || gui
->confirm_dialog (_("OK to override changes?"), 0)))
5868 /* --------------------------------------------------------------------------- */
5870 static const char new_syntax
[] = "New([name])";
5872 static const char new_help
[] = "Starts a new layout.";
5874 /* %start-doc actions New
5876 If a name is not given, one is prompted for.
5881 ActionNew (int argc
, char **argv
, Coord x
, Coord y
)
5883 char *name
= ARG (0);
5885 if (!PCB
->Changed
|| gui
->confirm_dialog (_("OK to clear layout data?"), 0))
5888 name
= strdup (name
);
5890 name
= gui
->prompt_for (_("Enter the layout name:"), "");
5895 notify_crosshair_change (false);
5896 /* do emergency saving
5897 * clear the old struct and allocate memory for the new one
5899 if (PCB
->Changed
&& Settings
.SaveInTMP
)
5902 PCB
= CreateNewPCB (true);
5903 PCB
->Data
->LayerN
= DEF_LAYER
;
5904 CreateNewPCBPost (PCB
, 1);
5906 /* setup the new name and reset some values to default */
5910 ResetStackAndVisibility ();
5911 SetCrosshairRange (0, 0, PCB
->MaxWidth
, PCB
->MaxHeight
);
5912 CenterDisplay (PCB
->MaxWidth
/ 2, PCB
->MaxHeight
/ 2);
5915 hid_action ("PCBChanged");
5916 notify_crosshair_change (true);
5922 /* ---------------------------------------------------------------------------
5923 * no operation, just for testing purposes
5924 * syntax: Bell(volume)
5927 ActionBell (char *volume
)
5932 /* --------------------------------------------------------------------------- */
5934 static const char pastebuffer_syntax
[] =
5935 "PasteBuffer(AddSelected|Clear|1..MAX_BUFFER)\n"
5936 "PasteBuffer(Rotate, 1..3)\n"
5937 "PasteBuffer(Convert|Save|Restore|Mirror)\n"
5938 "PasteBuffer(ToLayout, X, Y, units)";
5940 static const char pastebuffer_help
[] =
5941 "Various operations on the paste buffer.";
5943 /* %start-doc actions PasteBuffer
5945 There are a number of paste buffers; the actual limit is a
5946 compile-time constant @code{MAX_BUFFER} in @file{globalconst.h}. It
5947 is currently @code{5}. One of these is the ``current'' paste buffer,
5948 often referred to as ``the'' paste buffer.
5953 Copies the selected objects to the current paste buffer.
5956 Remove all objects from the current paste buffer.
5959 Convert the current paste buffer to an element. Vias are converted to
5960 pins, lines are converted to pads.
5963 Convert any elements in the paste buffer back to vias and lines.
5966 Flip all objects in the paste buffer vertically (up/down flip). To mirror
5967 horizontally, combine this with rotations.
5970 Rotates the current buffer. The number to pass is 1..3, where 1 means
5971 90 degrees counter clockwise, 2 means 180 degrees, and 3 means 90
5972 degrees clockwise (270 CCW).
5975 Saves any elements in the current buffer to the indicated file.
5978 Pastes any elements in the current buffer to the indicated X, Y
5979 coordinates in the layout. The @code{X} and @code{Y} are treated like
5980 @code{delta} is for many other objects. For each, if it's prefixed by
5981 @code{+} or @code{-}, then that amount is relative to the last
5982 location. Otherwise, it's absolute. Units can be
5983 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
5984 units, currently 1/100 mil.
5988 Selects the given buffer to be the current paste buffer.
5995 ActionPasteBuffer (int argc
, char **argv
, Coord x
, Coord y
)
5997 char *function
= argc
? argv
[0] : (char *)"";
5998 char *sbufnum
= argc
> 1 ? argv
[1] : (char *)"";
6000 static char *default_file
= NULL
;
6003 notify_crosshair_change (false);
6006 switch (GetFunctionID (function
))
6008 /* clear contents of paste buffer */
6010 ClearBuffer (PASTEBUFFER
);
6013 /* copies objects to paste buffer */
6015 AddSelectedToBuffer (PASTEBUFFER
, 0, 0, false);
6018 /* converts buffer contents into an element */
6020 ConvertBufferToElement (PASTEBUFFER
);
6023 /* break up element for editing */
6025 SmashBufferElement (PASTEBUFFER
);
6030 MirrorBuffer (PASTEBUFFER
);
6036 RotateBuffer (PASTEBUFFER
, (BYTE
) atoi (sbufnum
));
6037 SetCrosshairRangeToBuffer ();
6042 if (PASTEBUFFER
->Data
->ElementN
== 0)
6044 Message (_("Buffer has no elements!\n"));
6050 name
= gui
->fileselect (_("Save Paste Buffer As ..."),
6051 _("Choose a file to save the contents of the\n"
6052 "paste buffer to.\n"),
6053 default_file
, ".fp", "footprint",
6058 free (default_file
);
6059 default_file
= NULL
;
6063 default_file
= strdup (name
);
6074 if ((exist
= fopen (name
, "r")))
6078 confirm_dialog (_("File exists! Ok to overwrite?"), 0))
6079 SaveBufferElements (name
);
6082 SaveBufferElements (name
);
6084 if (free_name
&& name
)
6091 static Coord oldx
= 0, oldy
= 0;
6099 else if (argc
== 3 || argc
== 4)
6101 x
= GetValue (ARG (1), ARG (3), &absolute
);
6104 y
= GetValue (ARG (2), ARG (3), &absolute
);
6110 notify_crosshair_change (true);
6111 AFAIL (pastebuffer
);
6116 if (CopyPastebufferToLayout (x
, y
))
6117 SetChangedFlag (true);
6124 int number
= atoi (function
);
6126 /* correct number */
6128 SetBufferNumber (number
- 1);
6133 notify_crosshair_change (true);
6137 /* --------------------------------------------------------------------------- */
6139 static const char undo_syntax
[] = "Undo()\n"
6142 static const char undo_help
[] = "Undo recent changes.";
6144 /* %start-doc actions Undo
6146 The unlimited undo feature of @code{Pcb} allows you to recover from
6147 most operations that materially affect you work. Calling
6148 @code{Undo()} without any parameter recovers from the last (non-undo)
6149 operation. @code{ClearList} is used to release the allocated
6150 memory. @code{ClearList} is called whenever a new layout is started or
6151 loaded. See also @code{Redo} and @code{Atomic}.
6153 Note that undo groups operations by serial number; changes with the
6154 same serial number will be undone (or redone) as a group. See
6160 ActionUndo (int argc
, char **argv
, Coord x
, Coord y
)
6162 char *function
= ARG (0);
6163 if (!function
|| !*function
)
6165 /* don't allow undo in the middle of an operation */
6166 if (Settings
.Mode
!= POLYGONHOLE_MODE
&&
6167 Crosshair
.AttachedObject
.State
!= STATE_FIRST
)
6169 if (Crosshair
.AttachedBox
.State
!= STATE_FIRST
6170 && Settings
.Mode
!= ARC_MODE
)
6172 /* undo the last operation */
6174 notify_crosshair_change (false);
6175 if ((Settings
.Mode
== POLYGON_MODE
||
6176 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6177 Crosshair
.AttachedPolygon
.PointN
)
6179 GoToPreviousPoint ();
6180 notify_crosshair_change (true);
6183 /* move anchor point if undoing during line creation */
6184 if (Settings
.Mode
== LINE_MODE
)
6186 if (Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6188 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6189 Undo (true); /* undo the connection find */
6190 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
6191 SetLocalRef (0, 0, false);
6192 notify_crosshair_change (true);
6195 if (Crosshair
.AttachedLine
.State
== STATE_THIRD
)
6198 void *ptr1
, *ptr3
, *ptrtmp
;
6200 /* this search is guaranteed to succeed */
6201 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6203 Crosshair
.AttachedLine
.Point1
.X
,
6204 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6205 ptr2
= (LineTypePtr
) ptrtmp
;
6207 /* save both ends of line */
6208 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point1
.X
;
6209 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point1
.Y
;
6210 if ((type
= Undo (true)))
6211 SetChangedFlag (true);
6212 /* check that the undo was of the right type */
6213 if ((type
& UNDO_CREATE
) == 0)
6215 /* wrong undo type, restore anchor points */
6216 Crosshair
.AttachedLine
.Point2
.X
=
6217 Crosshair
.AttachedLine
.Point1
.X
;
6218 Crosshair
.AttachedLine
.Point2
.Y
=
6219 Crosshair
.AttachedLine
.Point1
.Y
;
6220 notify_crosshair_change (true);
6223 /* move to new anchor */
6224 Crosshair
.AttachedLine
.Point1
.X
=
6225 Crosshair
.AttachedLine
.Point2
.X
;
6226 Crosshair
.AttachedLine
.Point1
.Y
=
6227 Crosshair
.AttachedLine
.Point2
.Y
;
6228 /* check if an intermediate point was removed */
6229 if (type
& UNDO_REMOVE
)
6231 /* this search should find the restored line */
6232 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6235 Crosshair
.AttachedLine
.Point2
.X
,
6236 Crosshair
.AttachedLine
.Point2
.Y
, 0);
6237 ptr2
= (LineTypePtr
) ptrtmp
;
6238 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6240 /* undo loses FOUNDFLAG */
6241 SET_FLAG(FOUNDFLAG
, ptr2
);
6242 DrawLine (CURRENT
, ptr2
);
6244 Crosshair
.AttachedLine
.Point1
.X
=
6245 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point2
.X
;
6246 Crosshair
.AttachedLine
.Point1
.Y
=
6247 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point2
.Y
;
6249 FitCrosshairIntoGrid (Crosshair
.X
, Crosshair
.Y
);
6250 AdjustAttachedObjects ();
6251 if (--addedLines
== 0)
6253 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
6254 lastLayer
= CURRENT
;
6258 /* this search is guaranteed to succeed too */
6259 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6262 Crosshair
.AttachedLine
.Point1
.X
,
6263 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6264 ptr2
= (LineTypePtr
) ptrtmp
;
6265 lastLayer
= (LayerTypePtr
) ptr1
;
6267 notify_crosshair_change (true);
6271 if (Settings
.Mode
== ARC_MODE
)
6273 if (Crosshair
.AttachedBox
.State
== STATE_SECOND
)
6275 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
6276 notify_crosshair_change (true);
6279 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
)
6281 void *ptr1
, *ptr2
, *ptr3
;
6283 /* guaranteed to succeed */
6284 SearchObjectByLocation (ARC_TYPE
, &ptr1
, &ptr2
, &ptr3
,
6285 Crosshair
.AttachedBox
.Point1
.X
,
6286 Crosshair
.AttachedBox
.Point1
.Y
, 0);
6287 bx
= GetArcEnds ((ArcTypePtr
) ptr2
);
6288 Crosshair
.AttachedBox
.Point1
.X
=
6289 Crosshair
.AttachedBox
.Point2
.X
= bx
->X1
;
6290 Crosshair
.AttachedBox
.Point1
.Y
=
6291 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y1
;
6292 AdjustAttachedObjects ();
6293 if (--addedLines
== 0)
6294 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
6297 /* undo the last destructive operation */
6299 SetChangedFlag (true);
6303 switch (GetFunctionID (function
))
6305 /* clear 'undo objects' list */
6307 ClearUndoList (false);
6311 notify_crosshair_change (true);
6315 /* --------------------------------------------------------------------------- */
6317 static const char redo_syntax
[] = "Redo()";
6319 static const char redo_help
[] = "Redo recent \"undo\" operations.";
6321 /* %start-doc actions Redo
6323 This routine allows you to recover from the last undo command. You
6324 might want to do this if you thought that undo was going to revert
6325 something other than what it actually did (in case you are confused
6326 about which operations are un-doable), or if you have been backing up
6327 through a long undo list and over-shoot your stopping point. Any
6328 change that is made since the undo in question will trim the redo
6329 list. For example if you add ten lines, then undo three of them you
6330 could use redo to put them back, but if you move a line on the board
6331 before performing the redo, you will lose the ability to "redo" the
6332 three "undone" lines.
6337 ActionRedo (int argc
, char **argv
, Coord x
, Coord y
)
6339 if (((Settings
.Mode
== POLYGON_MODE
||
6340 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6341 Crosshair
.AttachedPolygon
.PointN
) ||
6342 Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6344 notify_crosshair_change (false);
6347 SetChangedFlag (true);
6348 if (Settings
.Mode
== LINE_MODE
&&
6349 Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
6351 LineType
*line
= g_list_last (CURRENT
->Line
)->data
;
6352 Crosshair
.AttachedLine
.Point1
.X
=
6353 Crosshair
.AttachedLine
.Point2
.X
= line
->Point2
.X
;
6354 Crosshair
.AttachedLine
.Point1
.Y
=
6355 Crosshair
.AttachedLine
.Point2
.Y
= line
->Point2
.Y
;
6359 notify_crosshair_change (true);
6363 /* --------------------------------------------------------------------------- */
6365 static const char polygon_syntax
[] = "Polygon(Close|PreviousPoint)";
6367 static const char polygon_help
[] = "Some polygon related stuff.";
6369 /* %start-doc actions Polygon
6371 Polygons need a special action routine to make life easier.
6376 Creates the final segment of the polygon. This may fail if clipping
6377 to 45 degree lines is switched on, in which case a warning is issued.
6380 Resets the newly entered corner to the previous one. The Undo action
6381 will call Polygon(PreviousPoint) when appropriate to do so.
6388 ActionPolygon (int argc
, char **argv
, Coord x
, Coord y
)
6390 char *function
= ARG (0);
6391 if (function
&& Settings
.Mode
== POLYGON_MODE
)
6393 notify_crosshair_change (false);
6394 switch (GetFunctionID (function
))
6396 /* close open polygon if possible */
6401 /* go back to the previous point */
6402 case F_PreviousPoint
:
6403 GoToPreviousPoint ();
6406 notify_crosshair_change (true);
6411 /* --------------------------------------------------------------------------- */
6413 static const char routestyle_syntax
[] = "RouteStyle(1|2|3|4)";
6415 static const char routestyle_help
[] =
6416 "Copies the indicated routing style into the current sizes.";
6418 /* %start-doc actions RouteStyle
6423 ActionRouteStyle (int argc
, char **argv
, Coord x
, Coord y
)
6425 char *str
= ARG (0);
6426 RouteStyleType
*rts
;
6431 number
= atoi (str
);
6432 if (number
> 0 && number
<= NUM_STYLES
)
6434 rts
= &PCB
->RouteStyle
[number
- 1];
6435 SetLineSize (rts
->Thick
);
6436 SetViaSize (rts
->Diameter
, true);
6437 SetViaDrillingHole (rts
->Hole
, true);
6438 SetKeepawayWidth (rts
->Keepaway
);
6439 hid_action("RouteStylesChanged");
6446 /* --------------------------------------------------------------------------- */
6448 static const char moveobject_syntax
[] = "MoveObject(X,Y,dim)";
6450 static const char moveobject_help
[] = "Moves the object under the crosshair.";
6452 /* %start-doc actions MoveObject
6454 The @code{X} and @code{Y} are treated like @code{delta} is for many
6455 other objects. For each, if it's prefixed by @code{+} or @code{-},
6456 then that amount is relative. Otherwise, it's absolute. Units can be
6457 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
6458 units, currently 1/100 mil.
6463 ActionMoveObject (int argc
, char **argv
, Coord x
, Coord y
)
6465 char *x_str
= ARG (0);
6466 char *y_str
= ARG (1);
6467 char *units
= ARG (2);
6469 bool absolute1
, absolute2
;
6470 void *ptr1
, *ptr2
, *ptr3
;
6473 ny
= GetValue (y_str
, units
, &absolute1
);
6474 nx
= GetValue (x_str
, units
, &absolute2
);
6476 type
= SearchScreen (x
, y
, MOVE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6477 if (type
== NO_TYPE
)
6479 Message (_("Nothing found under crosshair\n"));
6486 Crosshair
.AttachedObject
.RubberbandN
= 0;
6487 if (TEST_FLAG (RUBBERBANDFLAG
, PCB
))
6488 LookupRubberbandLines (type
, ptr1
, ptr2
, ptr3
);
6489 if (type
== ELEMENT_TYPE
)
6490 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
6491 MoveObjectAndRubberband (type
, ptr1
, ptr2
, ptr3
, nx
, ny
);
6492 SetChangedFlag (true);
6496 /* --------------------------------------------------------------------------- */
6498 static const char movetocurrentlayer_syntax
[] =
6499 "MoveToCurrentLayer(Object|SelectedObjects)";
6501 static const char movetocurrentlayer_help
[] =
6502 "Moves objects to the current layer.";
6504 /* %start-doc actions MoveToCurrentLayer
6506 Note that moving an element from a component layer to a solder layer,
6507 or from solder to component, won't automatically flip it. Use the
6508 @code{Flip()} action to do that.
6513 ActionMoveToCurrentLayer (int argc
, char **argv
, Coord x
, Coord y
)
6515 char *function
= ARG (0);
6518 switch (GetFunctionID (function
))
6523 void *ptr1
, *ptr2
, *ptr3
;
6525 gui
->get_coords (_("Select an Object"), &x
, &y
);
6527 SearchScreen (x
, y
, MOVETOLAYER_TYPES
,
6528 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6529 if (MoveObjectToLayer (type
, ptr1
, ptr2
, ptr3
, CURRENT
, false))
6530 SetChangedFlag (true);
6534 case F_SelectedObjects
:
6536 if (MoveSelectedObjectsToLayer (CURRENT
))
6537 SetChangedFlag (true);
6545 static const char setsame_syntax
[] = "SetSame()";
6547 static const char setsame_help
[] =
6548 "Sets current layer and sizes to match indicated item.";
6550 /* %start-doc actions SetSame
6552 When invoked over any line, arc, polygon, or via, this changes the
6553 current layer to be the layer that item is on, and changes the current
6554 sizes (thickness, keepaway, drill, etc) according to that item.
6559 ActionSetSame (int argc
, char **argv
, Coord x
, Coord y
)
6561 void *ptr1
, *ptr2
, *ptr3
;
6563 LayerTypePtr layer
= CURRENT
;
6565 type
= SearchScreen (x
, y
, CLONE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6566 /* set layer current and size from line or arc */
6570 notify_crosshair_change (false);
6571 Settings
.LineThickness
= ((LineTypePtr
) ptr2
)->Thickness
;
6572 Settings
.Keepaway
= ((LineTypePtr
) ptr2
)->Clearance
/ 2;
6573 layer
= (LayerTypePtr
) ptr1
;
6574 if (Settings
.Mode
!= LINE_MODE
)
6575 SetMode (LINE_MODE
);
6576 notify_crosshair_change (true);
6577 hid_action ("RouteStylesChanged");
6581 notify_crosshair_change (false);
6582 Settings
.LineThickness
= ((ArcTypePtr
) ptr2
)->Thickness
;
6583 Settings
.Keepaway
= ((ArcTypePtr
) ptr2
)->Clearance
/ 2;
6584 layer
= (LayerTypePtr
) ptr1
;
6585 if (Settings
.Mode
!= ARC_MODE
)
6587 notify_crosshair_change (true);
6588 hid_action ("RouteStylesChanged");
6592 layer
= (LayerTypePtr
) ptr1
;
6596 notify_crosshair_change (false);
6597 Settings
.ViaThickness
= ((PinTypePtr
) ptr2
)->Thickness
;
6598 Settings
.ViaDrillingHole
= ((PinTypePtr
) ptr2
)->DrillingHole
;
6599 Settings
.Keepaway
= ((PinTypePtr
) ptr2
)->Clearance
/ 2;
6600 if (Settings
.Mode
!= VIA_MODE
)
6602 notify_crosshair_change (true);
6603 hid_action ("RouteStylesChanged");
6609 if (layer
!= CURRENT
)
6611 ChangeGroupVisibility (GetLayerNumber (PCB
->Data
, layer
), true, true);
6618 /* --------------------------------------------------------------------------- */
6620 static const char setflag_syntax
[] =
6621 "SetFlag(Object|Selected|SelectedObjects, flag)\n"
6622 "SetFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6623 "SetFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6624 "SetFlag(SelectedElements, flag)\n"
6625 "flag = square | octagon | thermal | join";
6627 static const char setflag_help
[] = "Sets flags on objects.";
6629 /* %start-doc actions SetFlag
6631 Turns the given flag on, regardless of its previous setting. See
6635 SetFlag(SelectedPins,thermal)
6641 ActionSetFlag (int argc
, char **argv
, Coord x
, Coord y
)
6643 char *function
= ARG (0);
6644 char *flag
= ARG (1);
6645 ChangeFlag (function
, flag
, 1, "SetFlag");
6649 /* --------------------------------------------------------------------------- */
6651 static const char clrflag_syntax
[] =
6652 "ClrFlag(Object|Selected|SelectedObjects, flag)\n"
6653 "ClrFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6654 "ClrFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6655 "ClrFlag(SelectedElements, flag)\n"
6656 "flag = square | octagon | thermal | join";
6658 static const char clrflag_help
[] = "Clears flags on objects.";
6660 /* %start-doc actions ClrFlag
6662 Turns the given flag off, regardless of its previous setting. See
6666 ClrFlag(SelectedLines,join)
6672 ActionClrFlag (int argc
, char **argv
, Coord x
, Coord y
)
6674 char *function
= ARG (0);
6675 char *flag
= ARG (1);
6676 ChangeFlag (function
, flag
, 0, "ClrFlag");
6680 /* --------------------------------------------------------------------------- */
6682 static const char changeflag_syntax
[] =
6683 "ChangeFlag(Object|Selected|SelectedObjects, flag, value)\n"
6684 "ChangeFlag(SelectedLines|SelectedPins|SelectedVias, flag, value)\n"
6685 "ChangeFlag(SelectedPads|SelectedTexts|SelectedNames, flag, value)\n"
6686 "ChangeFlag(SelectedElements, flag, value)\n"
6687 "flag = square | octagon | thermal | join\n"
6690 static const char changeflag_help
[] = "Sets or clears flags on objects.";
6692 /* %start-doc actions ChangeFlag
6694 Toggles the given flag on the indicated object(s). The flag may be
6695 one of the flags listed above (square, octagon, thermal, join). The
6696 value may be the number 0 or 1. If the value is 0, the flag is
6697 cleared. If the value is 1, the flag is set.
6702 ActionChangeFlag (int argc
, char **argv
, Coord x
, Coord y
)
6704 char *function
= ARG (0);
6705 char *flag
= ARG (1);
6706 int value
= argc
> 2 ? atoi (argv
[2]) : -1;
6707 if (value
!= 0 && value
!= 1)
6710 ChangeFlag (function
, flag
, value
, "ChangeFlag");
6716 ChangeFlag (char *what
, char *flag_name
, int value
, char *cmd_name
)
6718 bool (*set_object
) (int, void *, void *, void *);
6719 bool (*set_selected
) (int);
6721 if (NSTRCMP (flag_name
, "square") == 0)
6723 set_object
= value
? SetObjectSquare
: ClrObjectSquare
;
6724 set_selected
= value
? SetSelectedSquare
: ClrSelectedSquare
;
6726 else if (NSTRCMP (flag_name
, "octagon") == 0)
6728 set_object
= value
? SetObjectOctagon
: ClrObjectOctagon
;
6729 set_selected
= value
? SetSelectedOctagon
: ClrSelectedOctagon
;
6731 else if (NSTRCMP (flag_name
, "join") == 0)
6733 /* Note: these are backwards, because the flag is "clear" but
6734 the command is "join". */
6735 set_object
= value
? ClrObjectJoin
: SetObjectJoin
;
6736 set_selected
= value
? ClrSelectedJoin
: SetSelectedJoin
;
6740 Message (_("%s(): Flag \"%s\" is not valid\n"), cmd_name
, flag_name
);
6744 switch (GetFunctionID (what
))
6749 void *ptr1
, *ptr2
, *ptr3
;
6752 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
6753 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6754 if (TEST_FLAG (LOCKFLAG
, (PinTypePtr
) ptr2
))
6755 Message (_("Sorry, the object is locked\n"));
6756 if (set_object (type
, ptr1
, ptr2
, ptr3
))
6757 SetChangedFlag (true);
6761 case F_SelectedVias
:
6762 if (set_selected (VIA_TYPE
))
6763 SetChangedFlag (true);
6766 case F_SelectedPins
:
6767 if (set_selected (PIN_TYPE
))
6768 SetChangedFlag (true);
6771 case F_SelectedPads
:
6772 if (set_selected (PAD_TYPE
))
6773 SetChangedFlag (true);
6776 case F_SelectedLines
:
6777 if (set_selected (LINE_TYPE
))
6778 SetChangedFlag (true);
6781 case F_SelectedTexts
:
6782 if (set_selected (TEXT_TYPE
))
6783 SetChangedFlag (true);
6786 case F_SelectedNames
:
6787 if (set_selected (ELEMENTNAME_TYPE
))
6788 SetChangedFlag (true);
6791 case F_SelectedElements
:
6792 if (set_selected (ELEMENT_TYPE
))
6793 SetChangedFlag (true);
6797 case F_SelectedObjects
:
6798 if (set_selected (CHANGESIZE_TYPES
))
6799 SetChangedFlag (true);
6804 /* --------------------------------------------------------------------------- */
6806 static const char executefile_syntax
[] = "ExecuteFile(filename)";
6808 static const char executefile_help
[] = "Run actions from the given file.";
6810 /* %start-doc actions ExecuteFile
6812 Lines starting with @code{#} are ignored.
6817 ActionExecuteFile (int argc
, char **argv
, Coord x
, Coord y
)
6826 AFAIL (executefile
);
6830 if ((fp
= fopen (fname
, "r")) == NULL
)
6832 fprintf (stderr
, _("Could not open actions file \"%s\".\n"), fname
);
6837 defer_needs_update
= 0;
6838 while (fgets (line
, sizeof (line
), fp
) != NULL
)
6843 /* eat the trailing newline */
6844 while (*sp
&& *sp
!= '\r' && *sp
!= '\n')
6848 /* eat leading spaces and tabs */
6850 while (*sp
&& (*sp
== ' ' || *sp
== '\t'))
6854 * if we have anything left and its not a comment line
6858 if (*sp
&& *sp
!= '#')
6860 /*Message ("%s : line %-3d : \"%s\"\n", fname, n, sp);*/
6861 hid_parse_actions (sp
);
6866 if (defer_needs_update
)
6868 IncrementUndoSerialNumber ();
6869 gui
->invalidate_all ();
6875 /* --------------------------------------------------------------------------- */
6878 ActionPSCalib (int argc
, char **argv
, Coord x
, Coord y
)
6880 HID
*ps
= hid_find_exporter ("ps");
6881 ps
->calibrate (0.0,0.0);
6885 /* --------------------------------------------------------------------------- */
6887 static ElementType
*element_cache
= NULL
;
6889 static ElementType
*
6890 find_element_by_refdes (char *refdes
)
6893 && NAMEONPCB_NAME(element_cache
)
6894 && strcmp (NAMEONPCB_NAME(element_cache
), refdes
) == 0)
6895 return element_cache
;
6897 ELEMENT_LOOP (PCB
->Data
);
6899 if (NAMEONPCB_NAME(element
)
6900 && strcmp (NAMEONPCB_NAME(element
), refdes
) == 0)
6902 element_cache
= element
;
6903 return element_cache
;
6910 static AttributeType
*
6911 lookup_attr (AttributeListTypePtr list
, const char *name
)
6914 for (i
=0; i
<list
->Number
; i
++)
6915 if (strcmp (list
->List
[i
].name
, name
) == 0)
6916 return & list
->List
[i
];
6921 delete_attr (AttributeListTypePtr list
, AttributeType
*attr
)
6923 int idx
= attr
- list
->List
;
6924 if (idx
< 0 || idx
>= list
->Number
)
6926 if (list
->Number
- idx
> 1)
6927 memmove (attr
, attr
+1, (list
->Number
- idx
- 1) * sizeof(AttributeType
));
6931 /* ---------------------------------------------------------------- */
6932 static const char elementlist_syntax
[] = "ElementList(Start|Done|Need,<refdes>,<footprint>,<value>)";
6934 static const char elementlist_help
[] = "Adds the given element if it doesn't already exist.";
6936 /* %start-doc actions elementlist
6941 Indicates the start of an element list; call this before any Need
6945 Searches the board for an element with a matching refdes.
6947 If found, the value and footprint are updated.
6949 If not found, a new element is created with the given footprint and value.
6952 Compares the list of elements needed since the most recent
6953 @code{start} with the list of elements actually on the board. Any
6954 elements that weren't listed are selected, so that the user may delete
6961 static int number_of_footprints_not_found
;
6964 parse_layout_attribute_units (char *name
, int def
)
6966 const char *as
= AttributeGet (PCB
, name
);
6969 return GetValue (as
, NULL
, NULL
);
6973 ActionElementList (int argc
, char **argv
, Coord x
, Coord y
)
6975 ElementType
*e
= NULL
;
6976 char *refdes
, *value
, *footprint
, *old
;
6978 char *function
= argv
[0];
6981 printf("Entered ActionElementList, executing function %s\n", function
);
6984 if (strcasecmp (function
, "start") == 0)
6986 ELEMENT_LOOP (PCB
->Data
);
6988 CLEAR_FLAG (FOUNDFLAG
, element
);
6991 element_cache
= NULL
;
6992 number_of_footprints_not_found
= 0;
6996 if (strcasecmp (function
, "done") == 0)
6998 ELEMENT_LOOP (PCB
->Data
);
7000 if (TEST_FLAG (FOUNDFLAG
, element
))
7002 CLEAR_FLAG (FOUNDFLAG
, element
);
7004 else if (! EMPTY_STRING_P (NAMEONPCB_NAME (element
)))
7006 /* Unnamed elements should remain untouched */
7007 SET_FLAG (SELECTEDFLAG
, element
);
7011 if (number_of_footprints_not_found
> 0)
7012 gui
->confirm_dialog ("Not all requested footprints were found.\n"
7013 "See the message log for details",
7018 if (strcasecmp (function
, "need") != 0)
7019 AFAIL (elementlist
);
7022 AFAIL (elementlist
);
7031 args
[0] = footprint
;
7036 printf(" ... footprint = %s\n", footprint
);
7037 printf(" ... refdes = %s\n", refdes
);
7038 printf(" ... value = %s\n", value
);
7041 e
= find_element_by_refdes (refdes
);
7048 printf(" ... Footprint not on board, need to add it.\n");
7050 /* Not on board, need to add it. */
7051 if (LoadFootprint(argc
, args
, x
, y
))
7053 number_of_footprints_not_found
++;
7057 nx
= PCB
->MaxWidth
/ 2;
7058 ny
= PCB
->MaxHeight
/ 2;
7059 d
= MIN (PCB
->MaxWidth
, PCB
->MaxHeight
) / 10;
7061 nx
= parse_layout_attribute_units ("import::newX", nx
);
7062 ny
= parse_layout_attribute_units ("import::newY", ny
);
7063 d
= parse_layout_attribute_units ("import::disperse", d
);
7067 nx
+= rand () % (d
*2) - d
;
7068 ny
+= rand () % (d
*2) - d
;
7073 if (nx
>= PCB
->MaxWidth
)
7074 nx
= PCB
->MaxWidth
- 1;
7077 if (ny
>= PCB
->MaxHeight
)
7078 ny
= PCB
->MaxHeight
- 1;
7080 /* Place components onto center of board. */
7081 if (CopyPastebufferToLayout (nx
, ny
))
7082 SetChangedFlag (true);
7085 else if (e
&& strcmp (DESCRIPTION_NAME(e
), footprint
) != 0)
7088 printf(" ... Footprint on board, but different from footprint loaded.\n");
7094 /* Different footprint, we need to swap them out. */
7095 if (LoadFootprint(argc
, args
, x
, y
))
7097 number_of_footprints_not_found
++;
7101 er
= ElementOrientation (e
);
7102 pe
= PASTEBUFFER
->Data
->Element
->data
;
7104 MirrorElementCoordinates (PASTEBUFFER
->Data
, pe
, pe
->MarkY
*2 - PCB
->MaxHeight
);
7105 pr
= ElementOrientation (pe
);
7111 RotateElementLowLevel (PASTEBUFFER
->Data
, pe
, pe
->MarkX
, pe
->MarkY
, (er
-pr
+4)%4);
7113 for (i
=0; i
<MAX_ELEMENTNAMES
; i
++)
7115 pe
->Name
[i
].X
= e
->Name
[i
].X
- mx
+ pe
->MarkX
;
7116 pe
->Name
[i
].Y
= e
->Name
[i
].Y
- my
+ pe
->MarkY
;
7117 pe
->Name
[i
].Direction
= e
->Name
[i
].Direction
;
7118 pe
->Name
[i
].Scale
= e
->Name
[i
].Scale
;
7123 if (CopyPastebufferToLayout (mx
, my
))
7124 SetChangedFlag (true);
7127 /* Now reload footprint */
7128 element_cache
= NULL
;
7129 e
= find_element_by_refdes (refdes
);
7131 old
= ChangeElementText (PCB
, PCB
->Data
, e
, NAMEONPCB_INDEX
, strdup (refdes
));
7134 old
= ChangeElementText (PCB
, PCB
->Data
, e
, VALUE_INDEX
, strdup (value
));
7138 SET_FLAG (FOUNDFLAG
, e
);
7141 printf(" ... Leaving ActionElementList.\n");
7147 /* ---------------------------------------------------------------- */
7148 static const char elementsetattr_syntax
[] = "ElementSetAttr(refdes,name[,value])";
7150 static const char elementsetattr_help
[] = "Sets or clears an element-specific attribute.";
7152 /* %start-doc actions elementsetattr
7154 If a value is specified, the named attribute is added (if not already
7155 present) or changed (if it is) to the given value. If the value is
7156 not specified, the given attribute is removed if present.
7161 ActionElementSetAttr (int argc
, char **argv
, Coord x
, Coord y
)
7163 ElementType
*e
= NULL
;
7164 char *refdes
, *name
, *value
;
7165 AttributeType
*attr
;
7169 AFAIL (changepinname
);
7176 ELEMENT_LOOP (PCB
->Data
);
7178 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
7188 Message(_("Cannot change attribute of %s - element not found\n"), refdes
);
7192 attr
= lookup_attr (&e
->Attributes
, name
);
7197 attr
->value
= strdup (value
);
7199 if (attr
&& ! value
)
7201 delete_attr (& e
->Attributes
, attr
);
7205 CreateNewAttribute (& e
->Attributes
, name
, value
);
7211 /* ---------------------------------------------------------------- */
7212 static const char execcommand_syntax
[] = "ExecCommand(command)";
7214 static const char execcommand_help
[] = "Runs a command.";
7216 /* %start-doc actions execcommand
7218 Runs the given command, which is a system executable.
7223 ActionExecCommand (int argc
, char **argv
, Coord x
, Coord y
)
7229 AFAIL (execcommand
);
7234 if (system (command
))
7239 /* ---------------------------------------------------------------- */
7242 pcb_spawnvp (char **argv
)
7244 #ifdef HAVE__SPAWNVP
7245 int result
= _spawnvp (_P_WAIT
, argv
[0], (const char * const *) argv
);
7256 Message(_("Cannot fork!"));
7262 execvp (argv
[0], argv
);
7275 /* ---------------------------------------------------------------- */
7277 * Creates a new temporary file name. Hopefully the operating system
7278 * provides a mkdtemp() function to securily create a temporary
7279 * directory with mode 0700. If so then that directory is created and
7280 * the returned string is made up of the directory plus the name
7281 * variable. For example:
7283 * tempfile_name_new ("myfile") might return
7284 * "/var/tmp/pcb.123456/myfile".
7286 * If mkdtemp() is not available then 'name' is ignored and the
7287 * insecure tmpnam() function is used.
7289 * Files/names created with tempfile_name_new() should be unlinked
7290 * with tempfile_unlink to make sure the temporary directory is also
7291 * removed when mkdtemp() is used.
7294 tempfile_name_new (char * name
)
7296 char *tmpfile
= NULL
;
7298 char *tmpdir
, *mytmpdir
;
7302 assert ( name
!= NULL
);
7305 #define TEMPLATE "pcb.XXXXXXXX"
7308 tmpdir
= getenv ("TMPDIR");
7310 /* FIXME -- what about win32? */
7311 if (tmpdir
== NULL
) {
7315 mytmpdir
= (char *) malloc (sizeof(char) *
7320 if (mytmpdir
== NULL
) {
7321 fprintf (stderr
, "%s(): malloc failed()\n", __FUNCTION__
);
7326 (void)strcat (mytmpdir
, tmpdir
);
7327 (void)strcat (mytmpdir
, PCB_DIR_SEPARATOR_S
);
7328 (void)strcat (mytmpdir
, TEMPLATE
);
7329 if (mkdtemp (mytmpdir
) == NULL
) {
7330 fprintf (stderr
, "%s(): mkdtemp (\"%s\") failed\n", __FUNCTION__
, mytmpdir
);
7336 len
= strlen (mytmpdir
) + /* the temp directory name */
7337 1 + /* the directory sep. */
7338 strlen (name
) + /* the file name */
7339 1 /* the \0 termination */
7342 tmpfile
= (char *) malloc (sizeof (char) * len
);
7345 (void)strcat (tmpfile
, mytmpdir
);
7346 (void)strcat (tmpfile
, PCB_DIR_SEPARATOR_S
);
7347 (void)strcat (tmpfile
, name
);
7353 * tmpnam() uses a static buffer so strdup() the result right away
7354 * in case someone decides to create multiple temp names.
7356 tmpfile
= strdup (tmpnam (NULL
));
7362 /* ---------------------------------------------------------------- */
7364 * Unlink a temporary file. If we have mkdtemp() then our temp file
7365 * lives in a temporary directory and we need to remove that directory
7369 tempfile_unlink (char * name
)
7372 /* SDB says: Want to keep old temp files for examiniation when debugging */
7381 /* it is possible that the file was never created so it is OK if the
7384 /* now figure out the directory name to remove */
7385 e
= strlen (name
) - 1;
7386 while (e
> 0 && name
[e
] != PCB_DIR_SEPARATOR_C
) {e
--;}
7388 dname
= strdup (name
);
7392 * at this point, e *should* point to the end of the directory part
7393 * but lets make sure.
7396 rc2
= rmdir (dname
);
7402 fprintf (stderr
, _("%s(): Unable to determine temp directory name from the temp file\n"),
7404 fprintf (stderr
, "%s(): \"%s\"\n",
7405 __FUNCTION__
, name
);
7409 /* name was allocated with malloc */
7414 * FIXME - should also return -1 if the temp file exists and was not
7422 int rc
= unlink (name
);
7425 fprintf (stderr
, _("Failed to unlink \"%s\"\n"), name
);
7436 /* ---------------------------------------------------------------- */
7437 static const char import_syntax
[] =
7439 "Import([gnetlist|make[,source,source,...]])\n"
7440 "Import(setnewpoint[,(mark|center|X,Y)])\n"
7441 "Import(setdisperse,D,units)\n";
7443 static const char import_help
[] = "Import schematics.";
7445 /* %start-doc actions Import
7447 Imports element and netlist data from the schematics (or some other
7448 source). The first parameter, which is optional, is the mode. If not
7449 specified, the @code{import::mode} attribute in the PCB is used.
7450 @code{gnetlist} means gnetlist is used to obtain the information from
7451 the schematics. @code{make} invokes @code{make}, assuming the user
7452 has a @code{Makefile} in the current directory. The @code{Makefile}
7453 will be invoked with the following variables set:
7458 The name of the .pcb file
7461 A space-separated list of source files
7464 The name of the file in which to put the command script, which may
7465 contain any @pcb{} actions. By default, this is a temporary file
7466 selected by @pcb{}, but if you specify an @code{import::outfile}
7467 attribute, that file name is used instead (and not automatically
7468 deleted afterwards).
7472 The target specified to be built is the first of these that apply:
7477 The target specified by an @code{import::target} attribute.
7480 The output file specified by an @code{import::outfile} attribute.
7483 If nothing else is specified, the target is @code{pcb_import}.
7487 If you specify an @code{import::makefile} attribute, then "-f <that
7488 file>" will be added to the command line.
7490 If you specify the mode, you may also specify the source files
7491 (schematics). If you do not specify any, the list of schematics is
7492 obtained by reading the @code{import::src@var{N}} attributes (like
7493 @code{import::src0}, @code{import::src1}, etc).
7495 For compatibility with future extensions to the import file format,
7496 the generated file @emph{must not} start with the two characters
7499 If a temporary file is needed the @code{TMPDIR} environment variable
7500 is used to select its location.
7502 Note that the programs @code{gnetlist} and @code{make} may be
7503 overridden by the user via the @code{make-program} and @code{gnetlist}
7504 @code{pcb} settings (i.e. in @code{~/.pcb/settings} or on the command
7507 If @pcb{} cannot determine which schematic(s) to import from, the GUI
7508 is called to let user choose (see @code{ImportGUI()}).
7510 Note that Import() doesn't delete anything - after an Import, elements
7511 which shouldn't be on the board are selected and may be removed once
7512 it's determined that the deletion is appropriate.
7514 If @code{Import()} is called with @code{setnewpoint}, then the location
7515 of new components can be specified. This is where parts show up when
7516 they're added to the board. The default is the center of the board.
7520 @item Import(setnewpoint)
7522 Prompts the user to click on the board somewhere, uses that point. If
7523 called by a hotkey, uses the current location of the crosshair.
7525 @item Import(setnewpoint,mark)
7527 Uses the location of the mark. If no mark is present, the point is
7530 @item Import(setnewpoint,center)
7532 Resets the point to the center of the board.
7534 @item Import(setnewpoint,X,Y,units)
7536 Sets the point to the specific coordinates given. Example:
7537 @code{Import(setnewpoint,50,25,mm)}
7541 Note that the X and Y locations are stored in attributes named
7542 @code{import::newX} and @code{import::newY} so you could change them
7543 manually if you wished.
7545 Calling @code{Import(setdisperse,D,units)} sets how much the newly
7546 placed elements are dispersed relative to the set point. For example,
7547 @code{Import(setdisperse,10,mm)} will offset each part randomly up to
7548 10mm away from the point. The default dispersion is 1/10th of the
7549 smallest board dimension. Dispersion is saved in the
7550 @code{import::disperse} attribute.
7555 ActionImport (int argc
, char **argv
, Coord x
, Coord y
)
7558 char **sources
= NULL
;
7562 printf("ActionImport: =========== Entering ActionImport ============\n");
7567 if (mode
&& strcasecmp (mode
, "setdisperse") == 0)
7576 const char *as
= AttributeGet (PCB
, "import::disperse");
7577 ds
= gui
->prompt_for(_("Enter dispersion:"), as
? as
: "0");
7581 sprintf(buf
, "%s%s", ds
, units
);
7582 AttributePut (PCB
, "import::disperse", buf
);
7585 AttributePut (PCB
, "import::disperse", ds
);
7586 if (ARG (1) == NULL
)
7591 if (mode
&& strcasecmp (mode
, "setnewpoint") == 0)
7593 const char *xs
, *ys
, *units
;
7603 gui
->get_coords (_("Click on a location"), &x
, &y
);
7605 else if (strcasecmp (xs
, "center") == 0)
7607 AttributeRemove (PCB
, "import::newX");
7608 AttributeRemove (PCB
, "import::newY");
7611 else if (strcasecmp (xs
, "mark") == 0)
7621 x
= GetValue (xs
, units
, NULL
);
7622 y
= GetValue (ys
, units
, NULL
);
7626 Message (_("Bad syntax for Import(setnewpoint)"));
7630 pcb_sprintf (buf
, "%$ms", x
);
7631 AttributePut (PCB
, "import::newX", buf
);
7632 pcb_sprintf (buf
, "%$ms", y
);
7633 AttributePut (PCB
, "import::newY", buf
);
7638 mode
= AttributeGet (PCB
, "import::mode");
7645 nsources
= argc
- 1;
7656 sprintf(sname
, "import::src%d", nsources
);
7657 src
= AttributeGet (PCB
, sname
);
7662 sources
= (char **) malloc ((nsources
+ 1) * sizeof (char *));
7666 sprintf(sname
, "import::src%d", nsources
);
7667 src
= AttributeGet (PCB
, sname
);
7668 sources
[nsources
] = src
;
7675 /* Replace .pcb with .sch and hope for the best. */
7676 char *pcbname
= PCB
->Filename
;
7678 char *dot
, *slash
, *bslash
;
7681 return hid_action("ImportGUI");
7683 schname
= (char *) malloc (strlen(pcbname
) + 5);
7684 strcpy (schname
, pcbname
);
7685 dot
= strchr (schname
, '.');
7686 slash
= strchr (schname
, '/');
7687 bslash
= strchr (schname
, '\\');
7688 if (dot
&& slash
&& dot
< slash
)
7690 if (dot
&& bslash
&& dot
< bslash
)
7694 strcat (schname
, ".sch");
7696 if (access (schname
, F_OK
))
7697 return hid_action("ImportGUI");
7699 sources
= (char **) malloc (2 * sizeof (char *));
7700 sources
[0] = schname
;
7705 if (strcasecmp (mode
, "gnetlist") == 0)
7707 char *tmpfile
= tempfile_name_new ("gnetlist_output");
7711 if (tmpfile
== NULL
) {
7712 Message (_("Could not create temp file"));
7716 cmd
= (char **) malloc ((7 + nsources
) * sizeof (char *));
7717 cmd
[0] = Settings
.GnetlistProgram
;
7723 for (i
=0; i
<nsources
; i
++)
7724 cmd
[6+i
] = sources
[i
];
7725 cmd
[6+nsources
] = NULL
;
7728 printf("ActionImport: =========== About to run gnetlist ============\n");
7729 printf("%s %s %s %s %s %s %s ...\n",
7730 cmd
[0], cmd
[1], cmd
[2], cmd
[3], cmd
[4], cmd
[5], cmd
[6]);
7733 if (pcb_spawnvp (cmd
))
7740 printf("ActionImport: =========== About to run ActionExecuteFile, file = %s ============\n", tmpfile
);
7745 ActionExecuteFile (1, cmd
, 0, 0);
7748 tempfile_unlink (tmpfile
);
7750 else if (strcasecmp (mode
, "make") == 0)
7752 int must_free_tmpfile
= 0;
7758 char *user_outfile
= NULL
;
7759 char *user_makefile
= NULL
;
7760 char *user_target
= NULL
;
7763 user_outfile
= AttributeGet (PCB
, "import::outfile");
7764 user_makefile
= AttributeGet (PCB
, "import::makefile");
7765 user_target
= AttributeGet (PCB
, "import::target");
7766 if (user_outfile
&& !user_target
)
7767 user_target
= user_outfile
;
7770 tmpfile
= user_outfile
;
7773 tmpfile
= tempfile_name_new ("gnetlist_output");
7774 if (tmpfile
== NULL
) {
7775 Message (_("Could not create temp file"));
7778 must_free_tmpfile
= 1;
7781 srclen
= sizeof("SRCLIST=") + 2;
7782 for (i
=0; i
<nsources
; i
++)
7783 srclen
+= strlen (sources
[i
]) + 2;
7784 srclist
= (char *) malloc (srclen
);
7785 strcpy (srclist
, "SRCLIST=");
7786 for (i
=0; i
<nsources
; i
++)
7789 strcat (srclist
, " ");
7790 strcat (srclist
, sources
[i
]);
7793 cmd
[0] = Settings
.MakeProgram
;
7795 cmd
[2] = Concat ("PCB=", PCB
->Filename
, NULL
);
7797 cmd
[4] = Concat ("OUT=", tmpfile
, NULL
);
7802 cmd
[i
++] = user_makefile
;
7804 cmd
[i
++] = user_target
? user_target
: (char *)"pcb_import";
7807 if (pcb_spawnvp (cmd
))
7809 if (must_free_tmpfile
)
7819 ActionExecuteFile (1, cmd
, 0, 0);
7824 if (must_free_tmpfile
)
7825 tempfile_unlink (tmpfile
);
7829 Message (_("Unknown import mode: %s\n"), mode
);
7834 AddAllRats (false, NULL
);
7837 printf("ActionImport: =========== Leaving ActionImport ============\n");
7843 /* ------------------------------------------------------------ */
7845 static const char attributes_syntax
[] =
7846 "Attributes(Layout|Layer|Element)\n"
7847 "Attributes(Layer,layername)";
7849 static const char attributes_help
[] =
7850 "Let the user edit the attributes of the layout, current or given\n"
7851 "layer, or selected element.";
7853 /* %start-doc actions Attributes
7855 This just pops up a dialog letting the user edit the attributes of the
7856 pcb, an element, or a layer.
7862 ActionAttributes (int argc
, char **argv
, Coord x
, Coord y
)
7864 char *function
= ARG (0);
7865 char *layername
= ARG (1);
7871 if (!gui
->edit_attributes
)
7873 Message (_("This GUI doesn't support Attribute Editing\n"));
7877 switch (GetFunctionID (function
))
7881 gui
->edit_attributes("Layout Attributes", &(PCB
->Attributes
));
7887 LayerType
*layer
= CURRENT
;
7892 for (i
=0; i
<max_copper_layer
; i
++)
7893 if (strcmp (PCB
->Data
->Layer
[i
].Name
, layername
) == 0)
7895 layer
= & (PCB
->Data
->Layer
[i
]);
7900 Message (_("No layer named %s\n"), layername
);
7904 buf
= (char *) malloc (strlen (layer
->Name
) + strlen ("Layer X Attributes"));
7905 sprintf (buf
, "Layer %s Attributes", layer
->Name
);
7906 gui
->edit_attributes(buf
, &(layer
->Attributes
));
7914 ElementType
*e
= NULL
;
7915 ELEMENT_LOOP (PCB
->Data
);
7917 if (TEST_FLAG (SELECTEDFLAG
, element
))
7926 Message (_("Too many elements selected\n"));
7932 gui
->get_coords (_("Click on an element"), &x
, &y
);
7934 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
7935 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
7936 e
= (ElementTypePtr
) ptrtmp
;
7939 Message (_("No element found there\n"));
7944 if (NAMEONPCB_NAME(e
))
7946 buf
= (char *) malloc (strlen (NAMEONPCB_NAME(e
)) + strlen ("Element X Attributes"));
7947 sprintf(buf
, "Element %s Attributes", NAMEONPCB_NAME(e
));
7951 buf
= strdup ("Unnamed Element Attributes");
7953 gui
->edit_attributes(buf
, &(e
->Attributes
));
7965 /* --------------------------------------------------------------------------- */
7967 HID_Action action_action_list
[] = {
7968 {"AddRats", 0, ActionAddRats
,
7969 addrats_help
, addrats_syntax
}
7971 {"Attributes", 0, ActionAttributes
,
7972 attributes_help
, attributes_syntax
}
7974 {"Atomic", 0, ActionAtomic
,
7975 atomic_help
, atomic_syntax
}
7977 {"AutoPlaceSelected", 0, ActionAutoPlaceSelected
,
7978 autoplace_help
, autoplace_syntax
}
7980 {"AutoRoute", 0, ActionAutoRoute
,
7981 autoroute_help
, autoroute_syntax
}
7983 {"ChangeClearSize", 0, ActionChangeClearSize
,
7984 changeclearsize_help
, changeclearsize_syntax
}
7986 {"ChangeDrillSize", 0, ActionChange2ndSize
,
7987 changedrillsize_help
, changedrillsize_syntax
}
7989 {"ChangeHole", 0, ActionChangeHole
,
7990 changehold_help
, changehold_syntax
}
7992 {"ChangeJoin", 0, ActionChangeJoin
,
7993 changejoin_help
, changejoin_syntax
}
7995 {"ChangeName", 0, ActionChangeName
,
7996 changename_help
, changename_syntax
}
7998 {"ChangePaste", 0, ActionChangePaste
,
7999 changepaste_help
, changepaste_syntax
}
8001 {"ChangePinName", 0, ActionChangePinName
,
8002 changepinname_help
, changepinname_syntax
}
8004 {"ChangeSize", 0, ActionChangeSize
,
8005 changesize_help
, changesize_syntax
}
8007 {"ChangeSquare", 0, ActionChangeSquare
,
8008 changesquare_help
, changesquare_syntax
}
8010 {"ChangeOctagon", 0, ActionChangeOctagon
,
8011 changeoctagon_help
, changeoctagon_syntax
}
8013 {"ClearSquare", 0, ActionClearSquare
,
8014 clearsquare_help
, clearsquare_syntax
}
8016 {"ClearOctagon", 0, ActionClearOctagon
,
8017 clearoctagon_help
, clearoctagon_syntax
}
8019 {"Connection", 0, ActionConnection
,
8020 connection_help
, connection_syntax
}
8022 {"Delete", 0, ActionDelete
,
8023 delete_help
, delete_syntax
}
8025 {"DeleteRats", 0, ActionDeleteRats
,
8026 deleterats_help
, deleterats_syntax
}
8028 {"DisperseElements", 0, ActionDisperseElements
,
8029 disperseelements_help
, disperseelements_syntax
}
8031 {"Display", 0, ActionDisplay
,
8032 display_help
, display_syntax
}
8034 {"DRC", 0, ActionDRCheck
,
8035 drc_help
, drc_syntax
}
8037 {"DumpLibrary", 0, ActionDumpLibrary
,
8038 dumplibrary_help
, dumplibrary_syntax
}
8040 {"ExecuteFile", 0, ActionExecuteFile
,
8041 executefile_help
, executefile_syntax
}
8043 {"Flip", N_("Click on Object or Flip Point"), ActionFlip
,
8044 flip_help
, flip_syntax
}
8046 {"LoadFrom", 0, ActionLoadFrom
,
8047 loadfrom_help
, loadfrom_syntax
}
8049 {"MarkCrosshair", 0, ActionMarkCrosshair
,
8050 markcrosshair_help
, markcrosshair_syntax
}
8052 {"Message", 0, ActionMessage
,
8053 message_help
, message_syntax
}
8055 {"MinMaskGap", 0, ActionMinMaskGap
,
8056 minmaskgap_help
, minmaskgap_syntax
}
8058 {"MinClearGap", 0, ActionMinClearGap
,
8059 mincleargap_help
, mincleargap_syntax
}
8061 {"Mode", 0, ActionMode
,
8062 mode_help
, mode_syntax
}
8064 {"MorphPolygon", 0, ActionMorphPolygon
,
8065 morphpolygon_help
, morphpolygon_syntax
}
8067 {"PasteBuffer", 0, ActionPasteBuffer
,
8068 pastebuffer_help
, pastebuffer_syntax
}
8070 {"Quit", 0, ActionQuit
,
8071 quit_help
, quit_syntax
}
8073 {"RemoveSelected", 0, ActionRemoveSelected
,
8074 removeselected_help
, removeselected_syntax
}
8076 {"Renumber", 0, ActionRenumber
,
8077 renumber_help
, renumber_syntax
}
8079 {"RipUp", 0, ActionRipUp
,
8080 ripup_help
, ripup_syntax
}
8082 {"Select", 0, ActionSelect
,
8083 select_help
, select_syntax
}
8085 {"Unselect", 0, ActionUnselect
,
8086 unselect_help
, unselect_syntax
}
8088 {"SaveSettings", 0, ActionSaveSettings
,
8089 savesettings_help
, savesettings_syntax
}
8091 {"SaveTo", 0, ActionSaveTo
,
8092 saveto_help
, saveto_syntax
}
8094 {"SetSquare", 0, ActionSetSquare
,
8095 setsquare_help
, setsquare_syntax
}
8097 {"SetOctagon", 0, ActionSetOctagon
,
8098 setoctagon_help
, setoctagon_syntax
}
8100 {"SetThermal", 0, ActionSetThermal
,
8101 setthermal_help
, setthermal_syntax
}
8103 {"SetValue", 0, ActionSetValue
,
8104 setvalue_help
, setvalue_syntax
}
8106 {"ToggleHideName", 0, ActionToggleHideName
,
8107 togglehidename_help
, togglehidename_syntax
}
8109 {"Undo", 0, ActionUndo
,
8110 undo_help
, undo_syntax
}
8112 {"Redo", 0, ActionRedo
,
8113 redo_help
, redo_syntax
}
8115 {"SetSame", N_("Select item to use attributes from"), ActionSetSame
,
8116 setsame_help
, setsame_syntax
}
8118 {"SetFlag", 0, ActionSetFlag
,
8119 setflag_help
, setflag_syntax
}
8121 {"ClrFlag", 0, ActionClrFlag
,
8122 clrflag_help
, clrflag_syntax
}
8124 {"ChangeFlag", 0, ActionChangeFlag
,
8125 changeflag_help
, changeflag_syntax
}
8127 {"Polygon", 0, ActionPolygon
,
8128 polygon_help
, polygon_syntax
}
8130 {"RouteStyle", 0, ActionRouteStyle
,
8131 routestyle_help
, routestyle_syntax
}
8133 {"MoveObject", N_("Select an Object"), ActionMoveObject
,
8134 moveobject_help
, moveobject_syntax
}
8136 {"MoveToCurrentLayer", 0, ActionMoveToCurrentLayer
,
8137 movetocurrentlayer_help
, movetocurrentlayer_syntax
}
8139 {"New", 0, ActionNew
,
8140 new_help
, new_syntax
}
8142 {"pscalib", 0, ActionPSCalib
}
8144 {"ElementList", 0, ActionElementList
,
8145 elementlist_help
, elementlist_syntax
}
8147 {"ElementSetAttr", 0, ActionElementSetAttr
,
8148 elementsetattr_help
, elementsetattr_syntax
}
8150 {"ExecCommand", 0, ActionExecCommand
,
8151 execcommand_help
, execcommand_syntax
}
8153 {"Import", 0, ActionImport
,
8154 import_help
, import_syntax
}
8158 REGISTER_ACTIONS (action_action_list
)