4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
6 * Copyright (C) 1997, 1998, 1999, 2000, 2001 Harry Eaton
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * Contact addresses for paper mail and Email:
23 * Harry Eaton, 6697 Buttonhole Ct, Columbia, MD 21044, USA
24 * haceaton@aplcomm.jhuapl.edu
28 /* action routines for output window
38 #include "autoplace.h"
39 #include "autoroute.h"
45 #include "crosshair.h"
59 /*#include "print.h"*/
64 #include "rubberband.h"
72 #include "pcb-printf.h"
75 #include <stdlib.h> /* rand() */
77 #ifdef HAVE_LIBDMALLOC
81 /* for fork() and friends */
86 #ifdef HAVE_SYS_WAIT_H
90 /* ---------------------------------------------------------------------------
120 F_ElementConnections
,
161 F_ResetLinesAndPolygons
,
162 F_ResetPinsViasAndPads
,
183 F_ToggleAllDirections
,
194 F_ToggleRubberBandMode
,
195 F_ToggleStartDirection
,
200 F_ToggleThindrawPoly
,
214 typedef struct /* used to identify subfunctions */
221 /* --------------------------------------------------------------------------- */
223 /* %start-doc actions 00delta
225 Many actions take a @code{delta} parameter as the last parameter,
226 which is an amount to change something. That @code{delta} may include
227 units, as an additional parameter, such as @code{Action(Object,5,mm)}.
228 If no units are specified, the default is PCB's native units
229 (currently 1/100 mil). Also, if the delta is prefixed by @code{+} or
230 @code{-}, the size is increased or decreased by that amount.
231 Otherwise, the size size is set to the given amount.
235 Action(Object,+0.5,mm)
239 Actions which take a @code{delta} parameter which do not accept all
240 these options will specify what they do take.
244 /* %start-doc actions 00objects
246 Many actions act on indicated objects on the board. They will have
247 parameters like @code{ToggleObject} or @code{SelectedVias} to indicate
248 what group of objects they act on. Unless otherwise specified, these
249 parameters are defined as follows:
255 Affects the object under the mouse pointer. If this action is invoked
256 from a menu or script, the user will be prompted to click on an
257 object, which is then the object affected.
260 @itemx SelectedObjects
262 Affects all objects which are currently selected. At least, all
263 selected objects for which the given action makes sense.
267 @itemx Selected@var{Type}
269 Affects all objects which are both selected and of the @var{Type} specified.
275 /* %start-doc actions 00macros
279 Pins, pads, and vias can have various shapes. All may be round. Pins
280 and pads may be square (obviously "square" pads are usually
281 rectangular). Pins and vias may be octagonal. When you change a
282 shape flag of an element, you actually change all of its pins and
285 Note that the square flag takes precedence over the octagon flag,
286 thus, if both the square and octagon flags are set, the object is
287 square. When the square flag is cleared, the pins and pads will be
288 either round or, if the octagon flag is set, octagonal.
294 /* ---------------------------------------------------------------------------
295 * some local identifiers
297 static PointType InsertedPoint
;
298 static LayerType
*lastLayer
;
311 bool Moving
; /* selected type clicked on */
312 int Hit
; /* move type clicked on */
319 static int defer_updates
= 0;
320 static int defer_needs_update
= 0;
322 static Cardinal polyIndex
= 0;
323 static bool saved_mode
= false;
324 #ifdef HAVE_LIBSTROKE
325 static bool mid_stroke
= false;
326 static BoxType StrokeBox
;
328 static FunctionType Functions
[] = {
329 {"AddSelected", F_AddSelected
},
331 {"AllConnections", F_AllConnections
},
332 {"AllRats", F_AllRats
},
333 {"AllUnusedPins", F_AllUnusedPins
},
337 {"Description", F_Description
},
338 {"Cancel", F_Cancel
},
339 {"Center", F_Center
},
341 {"ClearAndRedraw", F_ClearAndRedraw
},
342 {"ClearList", F_ClearList
},
344 {"Connection", F_Connection
},
345 {"Convert", F_Convert
},
347 {"CycleClip", F_CycleClip
},
348 {"CycleCrosshair", F_CycleCrosshair
},
349 {"DeleteRats", F_DeleteRats
},
351 {"DrillReport", F_DrillReport
},
352 {"Element", F_Element
},
353 {"ElementByName", F_ElementByName
},
354 {"ElementConnections", F_ElementConnections
},
355 {"ElementToBuffer", F_ElementToBuffer
},
356 {"Escape", F_Escape
},
358 {"FlipElement", F_FlipElement
},
359 {"FoundPins", F_FoundPins
},
361 {"InsertPoint", F_InsertPoint
},
363 {"Layout", F_Layout
},
364 {"LayoutAs", F_LayoutAs
},
365 {"LayoutToBuffer", F_LayoutToBuffer
},
367 {"LineSize", F_LineSize
},
369 {"Mirror", F_Mirror
},
371 {"NameOnPCB", F_NameOnPCB
},
372 {"Netlist", F_Netlist
},
373 {"NetByName", F_NetByName
},
375 {"Notify", F_Notify
},
376 {"Object", F_Object
},
377 {"ObjectByName", F_ObjectByName
},
378 {"PasteBuffer", F_PasteBuffer
},
379 {"PadByName", F_PadByName
},
380 {"PinByName", F_PinByName
},
381 {"PinOrPadName", F_PinOrPadName
},
382 {"Pinout", F_Pinout
},
383 {"Polygon", F_Polygon
},
384 {"PolygonHole", F_PolygonHole
},
385 {"PreviousPoint", F_PreviousPoint
},
386 {"RatsNest", F_RatsNest
},
387 {"Rectangle", F_Rectangle
},
388 {"Redraw", F_Redraw
},
389 {"Release", F_Release
},
390 {"Remove", F_Remove
},
391 {"RemoveSelected", F_RemoveSelected
},
392 {"Report", F_Report
},
394 {"ResetLinesAndPolygons", F_ResetLinesAndPolygons
},
395 {"ResetPinsViasAndPads", F_ResetPinsViasAndPads
},
396 {"Restore", F_Restore
},
397 {"Revert", F_Revert
},
398 {"Rotate", F_Rotate
},
400 {"Selected", F_Selected
},
401 {"SelectedArcs", F_SelectedArcs
},
402 {"SelectedElements", F_SelectedElements
},
403 {"SelectedLines", F_SelectedLines
},
404 {"SelectedNames", F_SelectedNames
},
405 {"SelectedObjects", F_SelectedObjects
},
406 {"SelectedPins", F_SelectedPins
},
407 {"SelectedPads", F_SelectedPads
},
408 {"SelectedRats", F_SelectedRats
},
409 {"SelectedTexts", F_SelectedTexts
},
410 {"SelectedVias", F_SelectedVias
},
411 {"Stroke", F_Stroke
},
413 {"TextByName", F_TextByName
},
414 {"TextScale", F_TextScale
},
415 {"Thermal", F_Thermal
},
416 {"ToLayout", F_ToLayout
},
417 {"Toggle45Degree", F_ToggleAllDirections
},
418 {"ToggleClearLine", F_ToggleClearLine
},
419 {"ToggleFullPoly", F_ToggleFullPoly
},
420 {"ToggleGrid", F_ToggleGrid
},
421 {"ToggleMask", F_ToggleMask
},
422 {"ToggleName", F_ToggleName
},
423 {"ToggleObject", F_ToggleObject
},
424 {"ToggleRubberBandMode", F_ToggleRubberBandMode
},
425 {"ToggleStartDirection", F_ToggleStartDirection
},
426 {"ToggleSnapPin", F_ToggleSnapPin
},
427 {"ToggleThindraw", F_ToggleThindraw
},
428 {"ToggleThindrawPoly", F_ToggleThindrawPoly
},
429 {"ToggleLockNames", F_ToggleLockNames
},
430 {"ToggleOnlyNames", F_ToggleOnlyNames
},
431 {"ToggleHideNames", F_ToggleHideNames
},
432 {"ToggleCheckPlanes", F_ToggleCheckPlanes
},
433 {"ToggleLocalRef", F_ToggleLocalRef
},
434 {"ToggleOrthoMove", F_ToggleOrthoMove
},
435 {"ToggleShowDRC", F_ToggleShowDRC
},
436 {"ToggleLiveRoute", F_ToggleLiveRoute
},
437 {"ToggleAutoDRC", F_ToggleAutoDRC
},
438 {"ToggleUniqueNames", F_ToggleUniqueNames
},
441 {"ViaByName", F_ViaByName
},
442 {"ViaSize", F_ViaSize
},
443 {"ViaDrillingHole", F_ViaDrillingHole
},
447 /* ---------------------------------------------------------------------------
448 * some local routines
450 static int GetFunctionID (String
);
451 static void AdjustAttachedBox (void);
452 static void NotifyLine (void);
453 static void NotifyBlock (void);
454 static void NotifyMode (void);
455 static void ClearWarnings (void);
456 #ifdef HAVE_LIBSTROKE
457 static void FinishStroke (void);
458 extern void stroke_init (void);
459 extern void stroke_record (int x
, int y
);
460 extern int stroke_trans (char *s
);
462 static void ChangeFlag (char *, char *, int, char *);
464 #define ARG(n) (argc > (n) ? argv[n] : NULL)
466 #ifdef HAVE_LIBSTROKE
468 /* ---------------------------------------------------------------------------
469 * FinishStroke - try to recognize the stroke sent
477 void *ptr1
, *ptr2
, *ptr3
;
480 if (stroke_trans (msg
))
486 if (Settings
.Mode
== LINE_MODE
)
496 RotateScreenObject (StrokeBox
.X1
, StrokeBox
.Y1
, SWAP_IDENT
? 1 : 3);
502 RotateScreenObject (StrokeBox
.X1
, StrokeBox
.Y1
, SWAP_IDENT
? 3 : 1);
508 SetMode (ARROW_MODE
);
533 /* XXX: FIXME: Call a zoom-extents action */
544 /* XXX: FIXME: Zoom to fit the box StrokeBox.[X1,Y1] - StrokeBox.[X2,Y2] */
548 Message (_("Unknown stroke %s\n"), msg
);
557 /* ---------------------------------------------------------------------------
558 * Clear warning color from pins/pads
563 Settings
.RatWarn
= false;
564 ALLPIN_LOOP (PCB
->Data
);
566 if (TEST_FLAG (WARNFLAG
, pin
))
568 CLEAR_FLAG (WARNFLAG
, pin
);
573 ALLPAD_LOOP (PCB
->Data
);
575 if (TEST_FLAG (WARNFLAG
, pad
))
577 CLEAR_FLAG (WARNFLAG
, pad
);
590 notify_crosshair_change (false);
592 if (Note
.Moving
&& !gui
->shift_is_pressed ())
594 Note
.Buffer
= Settings
.BufferNumber
;
595 SetBufferNumber (MAX_BUFFER
- 1);
596 ClearBuffer (PASTEBUFFER
);
597 AddSelectedToBuffer (PASTEBUFFER
, Note
.X
, Note
.Y
, true);
598 SaveUndoSerialNumber ();
602 SetMode (PASTEBUFFER_MODE
);
604 else if (Note
.Hit
&& !gui
->shift_is_pressed ())
608 SetMode (gui
->control_is_pressed ()? COPY_MODE
: MOVE_MODE
);
609 Crosshair
.AttachedObject
.Ptr1
= Note
.ptr1
;
610 Crosshair
.AttachedObject
.Ptr2
= Note
.ptr2
;
611 Crosshair
.AttachedObject
.Ptr3
= Note
.ptr3
;
612 Crosshair
.AttachedObject
.Type
= Note
.Hit
;
613 AttachForCopy (Note
.X
, Note
.Y
);
621 SaveUndoSerialNumber ();
626 /* unselect first if shift key not down */
627 if (!gui
->shift_is_pressed () && SelectBlock (&box
, false))
628 SetChangedFlag (true);
630 Crosshair
.AttachedBox
.Point1
.X
= Note
.X
;
631 Crosshair
.AttachedBox
.Point1
.Y
= Note
.Y
;
633 notify_crosshair_change (true);
651 Note
.Click
= false; /* inhibit timer action */
652 SaveUndoSerialNumber ();
653 /* unselect first if shift key not down */
654 if (!gui
->shift_is_pressed ())
656 if (SelectBlock (&box
, false))
657 SetChangedFlag (true);
665 RestoreUndoSerialNumber ();
667 SetChangedFlag (true);
671 else if (Note
.Moving
)
673 RestoreUndoSerialNumber ();
675 ClearBuffer (PASTEBUFFER
);
676 SetBufferNumber (Note
.Buffer
);
685 else if (Settings
.Mode
== ARROW_MODE
)
687 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
688 Crosshair
.AttachedBox
.Point2
.X
);
689 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
690 Crosshair
.AttachedBox
.Point2
.Y
);
691 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
692 Crosshair
.AttachedBox
.Point2
.X
);
693 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
694 Crosshair
.AttachedBox
.Point2
.Y
);
695 RestoreUndoSerialNumber ();
696 if (SelectBlock (&box
, true))
697 SetChangedFlag (true);
699 IncrementUndoSerialNumber ();
700 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
707 /* ---------------------------------------------------------------------------
708 * get function ID of passed string
711 static char function_hash
[HSIZE
];
712 static int hash_initted
= 0;
721 i
= (i
* 13) ^ (unsigned char)tolower((int) *s
);
724 i
= (unsigned int)i
% HSIZE
;
729 GetFunctionID (String Ident
)
739 if (HSIZE
< ENTRIES (Functions
) * 2)
741 fprintf(stderr
, _("Error: function hash size too small (%d vs %lu at %s:%d)\n"),
742 HSIZE
, (unsigned long) ENTRIES (Functions
)*2, __FILE__
, __LINE__
);
745 if (ENTRIES (Functions
) > 254)
747 /* Change 'char' to 'int' and remove this when we get to 256
749 fprintf(stderr
, _("Error: function hash type too small (%d vs %lu at %s:%d)\n"),
750 256, (unsigned long) ENTRIES (Functions
), __FILE__
, __LINE__
);
754 for (i
=ENTRIES (Functions
)-1; i
>=0; i
--)
756 h
= hashfunc (Functions
[i
].Identifier
);
757 while (function_hash
[h
])
759 function_hash
[h
] = i
+ 1;
763 i
= hashfunc (Ident
);
766 /* We enforce the "hash table bigger than function table" rule,
767 so we know there will be at least one zero entry to find. */
768 if (!function_hash
[i
])
770 if (!strcasecmp (Ident
, Functions
[function_hash
[i
]-1].Identifier
))
771 return ((int) Functions
[function_hash
[i
]-1].ID
);
776 /* ---------------------------------------------------------------------------
777 * set new coordinates if in 'RECTANGLE' mode
778 * the cursor shape is also adjusted
781 AdjustAttachedBox (void)
783 if (Settings
.Mode
== ARC_MODE
)
785 Crosshair
.AttachedBox
.otherway
= gui
->shift_is_pressed ();
788 switch (Crosshair
.AttachedBox
.State
)
790 case STATE_SECOND
: /* one corner is selected */
792 /* update coordinates */
793 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
794 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
800 /* ---------------------------------------------------------------------------
801 * adjusts the objects which are to be created like attached lines...
804 AdjustAttachedObjects (void)
807 switch (Settings
.Mode
)
809 /* update at least an attached block (selection) */
812 if (Crosshair
.AttachedBox
.State
)
814 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
815 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
819 /* rectangle creation mode */
822 AdjustAttachedBox ();
825 /* polygon creation mode */
827 case POLYGONHOLE_MODE
:
828 AdjustAttachedLine ();
830 /* line creation mode */
832 if (PCB
->RatDraw
|| PCB
->Clipping
== 0)
833 AdjustAttachedLine ();
835 AdjustTwoLine (PCB
->Clipping
- 1);
837 /* point insertion mode */
838 case INSERTPOINT_MODE
:
839 pnt
= AdjustInsertPoint ();
841 InsertedPoint
= *pnt
;
848 /* ---------------------------------------------------------------------------
849 * creates points of a line
855 void *ptr1
, *ptr2
, *ptr3
;
857 if (!Marked
.status
|| TEST_FLAG (LOCALREFFLAG
, PCB
))
858 SetLocalRef (Crosshair
.X
, Crosshair
.Y
, true);
859 switch (Crosshair
.AttachedLine
.State
)
861 case STATE_FIRST
: /* first point */
862 if (PCB
->RatDraw
&& SearchScreen (Crosshair
.X
, Crosshair
.Y
,
863 PAD_TYPE
| PIN_TYPE
, &ptr1
, &ptr1
,
869 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
871 type
= SearchScreen (Crosshair
.X
, Crosshair
.Y
,
872 PIN_TYPE
| PAD_TYPE
| VIA_TYPE
, &ptr1
, &ptr2
,
874 LookupConnection (Crosshair
.X
, Crosshair
.Y
, true, 1,
877 if (type
== PIN_TYPE
|| type
== VIA_TYPE
)
879 Crosshair
.AttachedLine
.Point1
.X
=
880 Crosshair
.AttachedLine
.Point2
.X
= ((PinType
*) ptr2
)->X
;
881 Crosshair
.AttachedLine
.Point1
.Y
=
882 Crosshair
.AttachedLine
.Point2
.Y
= ((PinType
*) ptr2
)->Y
;
884 else if (type
== PAD_TYPE
)
886 PadType
*pad
= (PadType
*) ptr2
;
887 double d1
= Distance (Crosshair
.X
, Crosshair
.Y
, pad
->Point1
.X
, pad
->Point1
.Y
);
888 double d2
= Distance (Crosshair
.X
, Crosshair
.Y
, pad
->Point2
.X
, pad
->Point2
.Y
);
891 Crosshair
.AttachedLine
.Point1
=
892 Crosshair
.AttachedLine
.Point2
= pad
->Point2
;
896 Crosshair
.AttachedLine
.Point1
=
897 Crosshair
.AttachedLine
.Point2
= pad
->Point1
;
902 Crosshair
.AttachedLine
.Point1
.X
=
903 Crosshair
.AttachedLine
.Point2
.X
= Crosshair
.X
;
904 Crosshair
.AttachedLine
.Point1
.Y
=
905 Crosshair
.AttachedLine
.Point2
.Y
= Crosshair
.Y
;
907 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
911 /* fall through to third state too */
913 default: /* all following points */
914 Crosshair
.AttachedLine
.State
= STATE_THIRD
;
919 /* ---------------------------------------------------------------------------
920 * create first or second corner of a marked block
925 notify_crosshair_change (false);
926 switch (Crosshair
.AttachedBox
.State
)
928 case STATE_FIRST
: /* setup first point */
929 Crosshair
.AttachedBox
.Point1
.X
=
930 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
931 Crosshair
.AttachedBox
.Point1
.Y
=
932 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
933 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
936 case STATE_SECOND
: /* setup second point */
937 Crosshair
.AttachedBox
.State
= STATE_THIRD
;
940 notify_crosshair_change (true);
944 /* ---------------------------------------------------------------------------
946 * does what's appropriate for the current mode setting. This normally
947 * means creation of an object at the current crosshair location.
949 * new created objects are added to the create undo list of course
954 void *ptr1
, *ptr2
, *ptr3
;
957 if (Settings
.RatWarn
)
959 switch (Settings
.Mode
)
967 /* do something after click time */
968 gui
->add_timer (click_cb
, CLICK_TIME
, hv
);
970 /* see if we clicked on something already selected
971 * (Note.Moving) or clicked on a MOVE_TYPE
974 for (test
= (SELECT_TYPES
| MOVE_TYPES
) & ~RATLINE_TYPE
;
977 type
= SearchScreen (Note
.X
, Note
.Y
, test
, &ptr1
, &ptr2
, &ptr3
);
978 if (!Note
.Hit
&& (type
& MOVE_TYPES
) &&
979 !TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
986 if (!Note
.Moving
&& (type
& SELECT_TYPES
) &&
987 TEST_FLAG (SELECTEDFLAG
, (PinType
*) ptr2
))
989 if ((Note
.Hit
&& Note
.Moving
) || type
== NO_TYPE
)
1001 Message (_("You must turn via visibility on before\n"
1002 "you can place vias\n"));
1005 if ((via
= CreateNewVia (PCB
->Data
, Note
.X
, Note
.Y
,
1006 Settings
.ViaThickness
, 2 * Settings
.Keepaway
,
1007 0, Settings
.ViaDrillingHole
, NULL
,
1008 NoFlags ())) != NULL
)
1010 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1011 if (gui
->shift_is_pressed ())
1012 ChangeObjectThermal (VIA_TYPE
, via
, via
, via
, PCB
->ThermStyle
);
1013 IncrementUndoSerialNumber ();
1022 switch (Crosshair
.AttachedBox
.State
)
1025 Crosshair
.AttachedBox
.Point1
.X
=
1026 Crosshair
.AttachedBox
.Point2
.X
= Note
.X
;
1027 Crosshair
.AttachedBox
.Point1
.Y
=
1028 Crosshair
.AttachedBox
.Point2
.Y
= Note
.Y
;
1029 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
1039 wx
= Note
.X
- Crosshair
.AttachedBox
.Point1
.X
;
1040 wy
= Note
.Y
- Crosshair
.AttachedBox
.Point1
.Y
;
1041 if (XOR (Crosshair
.AttachedBox
.otherway
, abs (wy
) > abs (wx
)))
1043 Crosshair
.AttachedBox
.Point2
.X
=
1044 Crosshair
.AttachedBox
.Point1
.X
+ abs (wy
) * SGNZ (wx
);
1045 sa
= (wx
>= 0) ? 0 : 180;
1047 if (abs (wy
) / 2 >= abs (wx
))
1048 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 45 : -45;
1051 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 90 : -90;
1055 Crosshair
.AttachedBox
.Point2
.Y
=
1056 Crosshair
.AttachedBox
.Point1
.Y
+ abs (wx
) * SGNZ (wy
);
1057 sa
= (wy
>= 0) ? -90 : 90;
1059 if (abs (wx
) / 2 >= abs (wy
))
1060 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -45 : 45;
1063 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -90 : 90;
1066 if (abs (wy
) > 0 && (arc
= CreateNewArcOnLayer (CURRENT
,
1090 bx
= GetArcEnds (arc
);
1091 Crosshair
.AttachedBox
.Point1
.X
=
1092 Crosshair
.AttachedBox
.Point2
.X
= bx
->X2
;
1093 Crosshair
.AttachedBox
.Point1
.Y
=
1094 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y2
;
1095 AddObjectToCreateUndoList (ARC_TYPE
, CURRENT
, arc
, arc
);
1096 IncrementUndoSerialNumber ();
1098 DrawArc (CURRENT
, arc
);
1100 Crosshair
.AttachedBox
.State
= STATE_THIRD
;
1109 type
= SearchScreen (Note
.X
, Note
.Y
, LOCK_TYPES
, &ptr1
, &ptr2
, &ptr3
);
1110 if (type
== ELEMENT_TYPE
)
1112 ElementType
*element
= (ElementType
*) ptr2
;
1114 TOGGLE_FLAG (LOCKFLAG
, element
);
1117 TOGGLE_FLAG (LOCKFLAG
, pin
);
1118 CLEAR_FLAG (SELECTEDFLAG
, pin
);
1123 TOGGLE_FLAG (LOCKFLAG
, pad
);
1124 CLEAR_FLAG (SELECTEDFLAG
, pad
);
1127 CLEAR_FLAG (SELECTEDFLAG
, element
);
1128 /* always re-draw it since I'm too lazy
1129 * to tell if a selected flag changed
1131 DrawElement (element
);
1133 SetChangedFlag (true);
1134 hid_actionl ("Report", "Object", NULL
);
1136 else if (type
!= NO_TYPE
)
1138 TextType
*thing
= (TextType
*) ptr3
;
1139 TOGGLE_FLAG (LOCKFLAG
, thing
);
1140 if (TEST_FLAG (LOCKFLAG
, thing
)
1141 && TEST_FLAG (SELECTEDFLAG
, thing
))
1143 /* this is not un-doable since LOCK isn't */
1144 CLEAR_FLAG (SELECTEDFLAG
, thing
);
1145 DrawObject (type
, ptr1
, ptr2
);
1148 SetChangedFlag (true);
1149 hid_actionl ("Report", "Object", NULL
);
1157 SearchScreen (Note
.X
, Note
.Y
, PIN_TYPES
, &ptr1
, &ptr2
,
1159 && !TEST_FLAG (HOLEFLAG
, (PinType
*) ptr3
))
1161 if (gui
->shift_is_pressed ())
1163 int tstyle
= GET_THERM (INDEXOFCURRENT
, (PinType
*) ptr3
);
1167 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, tstyle
);
1169 else if (GET_THERM (INDEXOFCURRENT
, (PinType
*) ptr3
))
1170 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, 0);
1172 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, PCB
->ThermStyle
);
1178 /* do update of position */
1180 if (Crosshair
.AttachedLine
.State
!= STATE_THIRD
)
1183 /* Remove anchor if clicking on start point;
1184 * this means we can't paint 0 length lines
1185 * which could be used for square SMD pads.
1186 * Instead use a very small delta, or change
1187 * the file after saving.
1189 if (Crosshair
.X
== Crosshair
.AttachedLine
.Point1
.X
1190 && Crosshair
.Y
== Crosshair
.AttachedLine
.Point1
.Y
)
1192 SetMode (LINE_MODE
);
1199 if ((line
= AddNet ()))
1202 AddObjectToCreateUndoList (RATLINE_TYPE
, line
, line
, line
);
1203 IncrementUndoSerialNumber ();
1205 Crosshair
.AttachedLine
.Point1
.X
=
1206 Crosshair
.AttachedLine
.Point2
.X
;
1207 Crosshair
.AttachedLine
.Point1
.Y
=
1208 Crosshair
.AttachedLine
.Point2
.Y
;
1214 /* create line if both ends are determined && length != 0 */
1217 int maybe_found_flag
;
1220 && Crosshair
.AttachedLine
.Point1
.X
==
1221 Crosshair
.AttachedLine
.Point2
.X
1222 && Crosshair
.AttachedLine
.Point1
.Y
==
1223 Crosshair
.AttachedLine
.Point2
.Y
1224 && (Crosshair
.AttachedLine
.Point2
.X
!= Note
.X
1225 || Crosshair
.AttachedLine
.Point2
.Y
!= Note
.Y
))
1227 /* We will only need to paint the second line segment.
1228 Since we only check for vias on the first segment,
1229 swap them so the non-empty segment is the first segment. */
1230 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1231 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1234 if (TEST_FLAG (AUTODRCFLAG
, PCB
)
1235 && ! TEST_SILK_LAYER (CURRENT
))
1236 maybe_found_flag
= FOUNDFLAG
;
1238 maybe_found_flag
= 0;
1240 if ((Crosshair
.AttachedLine
.Point1
.X
!=
1241 Crosshair
.AttachedLine
.Point2
.X
1242 || Crosshair
.AttachedLine
.Point1
.Y
!=
1243 Crosshair
.AttachedLine
.Point2
.Y
)
1245 CreateDrawnLineOnLayer (CURRENT
,
1246 Crosshair
.AttachedLine
.Point1
.X
,
1247 Crosshair
.AttachedLine
.Point1
.Y
,
1248 Crosshair
.AttachedLine
.Point2
.X
,
1249 Crosshair
.AttachedLine
.Point2
.Y
,
1250 Settings
.LineThickness
,
1251 2 * Settings
.Keepaway
,
1252 MakeFlags (maybe_found_flag
|
1255 PCB
) ? CLEARLINEFLAG
:
1261 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1262 DrawLine (CURRENT
, line
);
1263 /* place a via if vias are visible, the layer is
1264 in a new group since the last line and there
1265 isn't a pin already here */
1266 if (PCB
->ViaOn
&& GetLayerGroupNumberByPointer (CURRENT
) !=
1267 GetLayerGroupNumberByPointer (lastLayer
) &&
1268 SearchObjectByLocation (PIN_TYPES
, &ptr1
, &ptr2
, &ptr3
,
1269 Crosshair
.AttachedLine
.Point1
.X
,
1270 Crosshair
.AttachedLine
.Point1
.Y
,
1271 Settings
.ViaThickness
/ 2) ==
1274 CreateNewVia (PCB
->Data
,
1275 Crosshair
.AttachedLine
.Point1
.X
,
1276 Crosshair
.AttachedLine
.Point1
.Y
,
1277 Settings
.ViaThickness
,
1278 2 * Settings
.Keepaway
, 0,
1279 Settings
.ViaDrillingHole
, NULL
,
1280 NoFlags ())) != NULL
)
1282 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1285 /* copy the coordinates */
1286 Crosshair
.AttachedLine
.Point1
.X
=
1287 Crosshair
.AttachedLine
.Point2
.X
;
1288 Crosshair
.AttachedLine
.Point1
.Y
=
1289 Crosshair
.AttachedLine
.Point2
.Y
;
1290 IncrementUndoSerialNumber ();
1291 lastLayer
= CURRENT
;
1293 if (PCB
->Clipping
&& (Note
.X
!= Crosshair
.AttachedLine
.Point2
.X
1295 Crosshair
.AttachedLine
.Point2
.Y
)
1297 CreateDrawnLineOnLayer (CURRENT
,
1298 Crosshair
.AttachedLine
.Point2
.X
,
1299 Crosshair
.AttachedLine
.Point2
.Y
,
1301 Settings
.LineThickness
,
1302 2 * Settings
.Keepaway
,
1303 MakeFlags ((TEST_FLAG
1305 PCB
) ? FOUNDFLAG
: 0) |
1308 PCB
) ? CLEARLINEFLAG
:
1312 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1313 IncrementUndoSerialNumber ();
1314 DrawLine (CURRENT
, line
);
1315 /* move to new start point */
1316 Crosshair
.AttachedLine
.Point1
.X
= Note
.X
;
1317 Crosshair
.AttachedLine
.Point1
.Y
= Note
.Y
;
1318 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1319 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1320 if (TEST_FLAG (SWAPSTARTDIRFLAG
, PCB
))
1329 case RECTANGLE_MODE
:
1330 /* do update of position */
1333 /* create rectangle if both corners are determined
1334 * and width, height are != 0
1336 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
1337 Crosshair
.AttachedBox
.Point1
.X
!= Crosshair
.AttachedBox
.Point2
.X
&&
1338 Crosshair
.AttachedBox
.Point1
.Y
!= Crosshair
.AttachedBox
.Point2
.Y
)
1340 PolygonType
*polygon
;
1342 int flags
= CLEARPOLYFLAG
;
1343 if (TEST_FLAG (NEWFULLPOLYFLAG
, PCB
))
1344 flags
|= FULLPOLYFLAG
;
1345 if ((polygon
= CreateNewPolygonFromRectangle (CURRENT
,
1347 AttachedBox
.Point1
.X
,
1349 AttachedBox
.Point1
.Y
,
1351 AttachedBox
.Point2
.X
,
1353 AttachedBox
.Point2
.Y
,
1358 AddObjectToCreateUndoList (POLYGON_TYPE
, CURRENT
,
1360 IncrementUndoSerialNumber ();
1361 DrawPolygon (CURRENT
, polygon
);
1365 /* reset state to 'first corner' */
1366 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
1374 if ((string
= gui
->prompt_for (_("Enter text:"), "")) != NULL
)
1376 if (strlen(string
) > 0)
1379 int flag
= CLEARLINEFLAG
;
1381 if (GetLayerGroupNumberByNumber (INDEXOFCURRENT
) ==
1382 GetLayerGroupNumberByNumber (solder_silk_layer
))
1383 flag
|= ONSOLDERFLAG
;
1384 if ((text
= CreateNewText (CURRENT
, &PCB
->Font
, Note
.X
,
1385 Note
.Y
, 0, Settings
.TextScale
,
1386 string
, MakeFlags (flag
))) != NULL
)
1388 AddObjectToCreateUndoList (TEXT_TYPE
, CURRENT
, text
, text
);
1389 IncrementUndoSerialNumber ();
1390 DrawText (CURRENT
, text
);
1401 PointType
*points
= Crosshair
.AttachedPolygon
.Points
;
1402 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1404 /* do update of position; use the 'LINE_MODE' mechanism */
1407 /* check if this is the last point of a polygon */
1409 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1410 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1412 CopyAttachedPolygonToLayer ();
1417 /* create new point if it's the first one or if it's
1418 * different to the last one
1421 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1422 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1424 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1425 Crosshair
.AttachedLine
.Point2
.X
,
1426 Crosshair
.AttachedLine
.Point2
.Y
);
1428 /* copy the coordinates */
1429 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1430 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1435 case POLYGONHOLE_MODE
:
1437 switch (Crosshair
.AttachedObject
.State
)
1439 /* first notify, lookup object */
1441 Crosshair
.AttachedObject
.Type
=
1442 SearchScreen (Note
.X
, Note
.Y
, POLYGON_TYPE
,
1443 &Crosshair
.AttachedObject
.Ptr1
,
1444 &Crosshair
.AttachedObject
.Ptr2
,
1445 &Crosshair
.AttachedObject
.Ptr3
);
1447 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1449 if (TEST_FLAG (LOCKFLAG
, (PolygonType
*)
1450 Crosshair
.AttachedObject
.Ptr2
))
1452 Message (_("Sorry, the object is locked\n"));
1453 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1457 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1461 /* second notify, insert new point into object */
1464 PointType
*points
= Crosshair
.AttachedPolygon
.Points
;
1465 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1466 POLYAREA
*original
, *new_hole
, *result
;
1469 /* do update of position; use the 'LINE_MODE' mechanism */
1472 /* check if this is the last point of a polygon */
1474 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1475 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1477 /* Create POLYAREAs from the original polygon
1478 * and the new hole polygon */
1479 original
= PolygonToPoly ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
);
1480 new_hole
= PolygonToPoly (&Crosshair
.AttachedPolygon
);
1482 /* Subtract the hole from the original polygon shape */
1483 poly_Boolean_free (original
, new_hole
, &result
, PBO_SUB
);
1485 /* Convert the resulting polygon(s) into a new set of nodes
1486 * and place them on the page. Delete the original polygon.
1488 SaveUndoSerialNumber ();
1489 Flags
= ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
)->Flags
;
1490 PolyToPolygonsOnLayer (PCB
->Data
, (LayerType
*)Crosshair
.AttachedObject
.Ptr1
,
1492 RemoveObject (POLYGON_TYPE
,
1493 Crosshair
.AttachedObject
.Ptr1
,
1494 Crosshair
.AttachedObject
.Ptr2
,
1495 Crosshair
.AttachedObject
.Ptr3
);
1496 RestoreUndoSerialNumber ();
1497 IncrementUndoSerialNumber ();
1500 /* reset state of attached line */
1501 memset (&Crosshair
.AttachedPolygon
, 0, sizeof (PolygonType
));
1502 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
1508 /* create new point if it's the first one or if it's
1509 * different to the last one
1512 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1513 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1515 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1516 Crosshair
.AttachedLine
.Point2
.X
,
1517 Crosshair
.AttachedLine
.Point2
.Y
);
1519 /* copy the coordinates */
1520 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1521 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1530 case PASTEBUFFER_MODE
:
1532 TextType estr
[MAX_ELEMENTNAMES
];
1535 if (gui
->shift_is_pressed ())
1538 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1540 if (type
== ELEMENT_TYPE
)
1542 e
= (ElementType
*) ptr1
;
1547 memcpy (estr
, e
->Name
,
1548 MAX_ELEMENTNAMES
* sizeof (TextType
));
1549 for (i
= 0; i
< MAX_ELEMENTNAMES
; ++i
)
1550 estr
[i
].TextString
= estr
[i
].TextString
? strdup(estr
[i
].TextString
) : NULL
;
1555 if (CopyPastebufferToLayout (Note
.X
, Note
.Y
))
1556 SetChangedFlag (true);
1560 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1562 if (type
== ELEMENT_TYPE
&& ptr1
)
1565 e
= (ElementType
*) ptr1
;
1567 save_n
= NAME_INDEX (PCB
);
1569 for (i
= 0; i
< MAX_ELEMENTNAMES
; i
++)
1572 EraseElementName (e
);
1573 r_delete_entry (PCB
->Data
->name_tree
[i
],
1574 (BoxType
*) & (e
->Name
[i
]));
1575 memcpy (&(e
->Name
[i
]), &(estr
[i
]), sizeof (TextType
));
1576 e
->Name
[i
].Element
= e
;
1577 SetTextBoundingBox (&PCB
->Font
, &(e
->Name
[i
]));
1578 r_insert_entry (PCB
->Data
->name_tree
[i
],
1579 (BoxType
*) & (e
->Name
[i
]), 0);
1581 DrawElementName (e
);
1590 SearchScreen (Note
.X
, Note
.Y
, REMOVE_TYPES
, &ptr1
, &ptr2
,
1593 if (TEST_FLAG (LOCKFLAG
, (LineType
*) ptr2
))
1595 Message (_("Sorry, the object is locked\n"));
1598 if (type
== ELEMENT_TYPE
)
1600 RubberbandType
*ptr
;
1603 Crosshair
.AttachedObject
.RubberbandN
= 0;
1604 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
1605 ptr
= Crosshair
.AttachedObject
.Rubberband
;
1606 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
; i
++)
1609 EraseRat ((RatType
*) ptr
->Line
);
1610 if (TEST_FLAG (RUBBERENDFLAG
, ptr
->Line
))
1611 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
1612 ptr
->Line
, ptr
->Line
,
1615 TOGGLE_FLAG (RUBBERENDFLAG
, ptr
->Line
); /* only remove line once */
1619 RemoveObject (type
, ptr1
, ptr2
, ptr3
);
1620 IncrementUndoSerialNumber ();
1621 SetChangedFlag (true);
1626 RotateScreenObject (Note
.X
, Note
.Y
,
1627 gui
->shift_is_pressed ()? (SWAP_IDENT
?
1629 : (SWAP_IDENT
? 3 : 1));
1632 /* both are almost the same */
1635 switch (Crosshair
.AttachedObject
.State
)
1637 /* first notify, lookup object */
1640 int types
= (Settings
.Mode
== COPY_MODE
) ?
1641 COPY_TYPES
: MOVE_TYPES
;
1643 Crosshair
.AttachedObject
.Type
=
1644 SearchScreen (Note
.X
, Note
.Y
, types
,
1645 &Crosshair
.AttachedObject
.Ptr1
,
1646 &Crosshair
.AttachedObject
.Ptr2
,
1647 &Crosshair
.AttachedObject
.Ptr3
);
1648 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1650 if (Settings
.Mode
== MOVE_MODE
&&
1651 TEST_FLAG (LOCKFLAG
, (PinType
*)
1652 Crosshair
.AttachedObject
.Ptr2
))
1654 Message (_("Sorry, the object is locked\n"));
1655 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1658 AttachForCopy (Note
.X
, Note
.Y
);
1663 /* second notify, move or copy object */
1665 if (Settings
.Mode
== COPY_MODE
)
1666 CopyObject (Crosshair
.AttachedObject
.Type
,
1667 Crosshair
.AttachedObject
.Ptr1
,
1668 Crosshair
.AttachedObject
.Ptr2
,
1669 Crosshair
.AttachedObject
.Ptr3
,
1670 Note
.X
- Crosshair
.AttachedObject
.X
,
1671 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1674 MoveObjectAndRubberband (Crosshair
.AttachedObject
.Type
,
1675 Crosshair
.AttachedObject
.Ptr1
,
1676 Crosshair
.AttachedObject
.Ptr2
,
1677 Crosshair
.AttachedObject
.Ptr3
,
1678 Note
.X
- Crosshair
.AttachedObject
.X
,
1679 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1680 SetLocalRef (0, 0, false);
1682 SetChangedFlag (true);
1684 /* reset identifiers */
1685 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1686 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1691 /* insert a point into a polygon/line/... */
1692 case INSERTPOINT_MODE
:
1693 switch (Crosshair
.AttachedObject
.State
)
1695 /* first notify, lookup object */
1697 Crosshair
.AttachedObject
.Type
=
1698 SearchScreen (Note
.X
, Note
.Y
, INSERT_TYPES
,
1699 &Crosshair
.AttachedObject
.Ptr1
,
1700 &Crosshair
.AttachedObject
.Ptr2
,
1701 &Crosshair
.AttachedObject
.Ptr3
);
1703 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1705 if (TEST_FLAG (LOCKFLAG
, (PolygonType
*)
1706 Crosshair
.AttachedObject
.Ptr2
))
1708 Message (_("Sorry, the object is locked\n"));
1709 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1714 /* get starting point of nearest segment */
1715 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1718 (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
;
1720 GetLowestDistancePolygonPoint (fake
.poly
, Note
.X
,
1722 fake
.line
.Point1
= fake
.poly
->Points
[polyIndex
];
1723 fake
.line
.Point2
= fake
.poly
->Points
[
1724 prev_contour_point (fake
.poly
, polyIndex
)];
1725 Crosshair
.AttachedObject
.Ptr2
= &fake
.line
;
1728 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1729 InsertedPoint
= *AdjustInsertPoint ();
1734 /* second notify, insert new point into object */
1736 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1737 InsertPointIntoObject (POLYGON_TYPE
,
1738 Crosshair
.AttachedObject
.Ptr1
, fake
.poly
,
1740 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1742 InsertPointIntoObject (Crosshair
.AttachedObject
.Type
,
1743 Crosshair
.AttachedObject
.Ptr1
,
1744 Crosshair
.AttachedObject
.Ptr2
,
1746 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1747 SetChangedFlag (true);
1749 /* reset identifiers */
1750 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1751 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1759 /* --------------------------------------------------------------------------- */
1761 static const char atomic_syntax
[] = "Atomic(Save|Restore|Close|Block)";
1763 static const char atomic_help
[] = "Save or restore the undo serial number.";
1765 /* %start-doc actions Atomic
1767 This action allows making multiple-action bindings into an atomic
1768 operation that will be undone by a single Undo command. For example,
1769 to optimize rat lines, you'd delete the rats and re-add them. To
1770 group these into a single undo, you'd want the deletions and the
1771 additions to have the same undo serial number. So, you @code{Save},
1772 delete the rats, @code{Restore}, add the rats - using the same serial
1773 number as the deletes, then @code{Block}, which checks to see if the
1774 deletions or additions actually did anything. If not, the serial
1775 number is set to the saved number, as there's nothing to undo. If
1776 something did happen, the serial number is incremented so that these
1777 actions are counted as a single undo step.
1782 Saves the undo serial number.
1785 Returns it to the last saved number.
1788 Sets it to 1 greater than the last save.
1791 Does a Restore if there was nothing to undo, else does a Close.
1798 ActionAtomic (int argc
, char **argv
, Coord x
, Coord y
)
1803 switch (GetFunctionID (argv
[0]))
1806 SaveUndoSerialNumber ();
1809 RestoreUndoSerialNumber ();
1812 RestoreUndoSerialNumber ();
1813 IncrementUndoSerialNumber ();
1816 RestoreUndoSerialNumber ();
1818 IncrementUndoSerialNumber ();
1824 /* -------------------------------------------------------------------------- */
1826 static const char drc_syntax
[] = "DRC()";
1828 static const char drc_help
[] = "Invoke the DRC check.";
1830 /* %start-doc actions DRC
1832 Note that the design rule check uses the current board rule settings,
1833 not the current style settings.
1838 ActionDRCheck (int argc
, char **argv
, Coord x
, Coord y
)
1842 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1844 Message (_("%m+Rules are minspace %$mS, minoverlap %$mS "
1845 "minwidth %$mS, minsilk %$mS\n"
1846 "min drill %$mS, min annular ring %$mS\n"),
1847 Settings
.grid_unit
->allow
,
1848 PCB
->Bloat
, PCB
->Shrink
,
1849 PCB
->minWid
, PCB
->minSlk
,
1850 PCB
->minDrill
, PCB
->minRing
);
1853 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1856 Message (_("No DRC problems found.\n"));
1858 Message (_("Found %d design rule errors.\n"), count
);
1860 Message (_("Aborted DRC after %d design rule errors.\n"), -count
);
1865 /* -------------------------------------------------------------------------- */
1867 static const char dumplibrary_syntax
[] = "DumpLibrary()";
1869 static const char dumplibrary_help
[] =
1870 "Display the entire contents of the libraries.";
1872 /* %start-doc actions DumpLibrary
1878 ActionDumpLibrary (int argc
, char **argv
, Coord x
, Coord y
)
1882 printf ("**** Do not count on this format. It will change ****\n\n");
1883 printf ("MenuN = %d\n", Library
.MenuN
);
1884 printf ("MenuMax = %d\n", Library
.MenuMax
);
1885 for (i
= 0; i
< Library
.MenuN
; i
++)
1887 printf ("Library #%d:\n", i
);
1888 printf (" EntryN = %d\n", Library
.Menu
[i
].EntryN
);
1889 printf (" EntryMax = %d\n", Library
.Menu
[i
].EntryMax
);
1890 printf (" Name = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Name
));
1891 printf (" directory = \"%s\"\n",
1892 UNKNOWN (Library
.Menu
[i
].directory
));
1893 printf (" Style = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Style
));
1894 printf (" flag = %d\n", Library
.Menu
[i
].flag
);
1896 for (j
= 0; j
< Library
.Menu
[i
].EntryN
; j
++)
1898 printf (" #%4d: ", j
);
1899 if (Library
.Menu
[i
].Entry
[j
].Template
== (char *) -1)
1901 printf ("newlib: \"%s\"\n",
1902 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
));
1906 printf ("\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"\n",
1907 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
),
1908 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Template
),
1909 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Package
),
1910 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Value
),
1911 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Description
));
1919 /* -------------------------------------------------------------------------- */
1921 static const char flip_syntax
[] = "Flip(Object|Selected|SelectedElements)";
1923 static const char flip_help
[] =
1924 "Flip an element to the opposite side of the board.";
1926 /* %start-doc actions Flip
1928 Note that the location of the element will be symmetric about the
1929 cursor location; i.e. if the part you are pointing at will still be at
1930 the same spot once the element is on the other side. When flipping
1931 multiple elements, this retains their positions relative to each
1932 other, not their absolute positions on the board.
1937 ActionFlip (int argc
, char **argv
, Coord x
, Coord y
)
1939 char *function
= ARG (0);
1940 ElementType
*element
;
1946 switch (GetFunctionID (function
))
1949 if ((SearchScreen (x
, y
, ELEMENT_TYPE
,
1950 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
1952 element
= (ElementType
*) ptrtmp
;
1953 ChangeElementSide (element
, 2 * Crosshair
.Y
- PCB
->MaxHeight
);
1954 IncrementUndoSerialNumber ();
1959 case F_SelectedElements
:
1960 ChangeSelectedElementSide ();
1973 /* -------------------------------------------------------------------------- */
1975 static const char message_syntax
[] = "Message(message)";
1977 static const char message_help
[] = "Writes a message to the log window.";
1979 /* %start-doc actions Message
1981 This action displays a message to the log window. This action is primarily
1982 provided for use by other programs which may interface with PCB. If
1983 multiple arguments are given, each one is sent to the log window
1984 followed by a newline.
1989 ActionMessage (int argc
, char **argv
, Coord x
, Coord y
)
1996 for (i
= 0; i
< argc
; i
++)
2006 /* -------------------------------------------------------------------------- */
2008 static const char setthermal_syntax
[] =
2009 "SetThermal(Object|SelectedPins|SelectedVias|Selected, Style)";
2011 static const char setthermal_help
[] =
2012 "Set the thermal (on the current layer) of pins or vias to the given style.\n"
2013 "Style = 0 means no thermal.\n"
2014 "Style = 1 has diagonal fingers with sharp edges.\n"
2015 "Style = 2 has horizontal and vertical fingers with sharp edges.\n"
2016 "Style = 3 is a solid connection to the plane."
2017 "Style = 4 has diagonal fingers with rounded edges.\n"
2018 "Style = 5 has horizontal and vertical fingers with rounded edges.\n";
2020 /* %start-doc actions SetThermal
2022 This changes how/whether pins or vias connect to any rectangle or polygon
2023 on the current layer. The first argument can specify one object, or all
2024 selected pins, or all selected vias, or all selected pins and vias.
2025 The second argument specifies the style of connection.
2026 There are 5 possibilities:
2028 1 - 45 degree fingers with sharp edges,
2029 2 - horizontal & vertical fingers with sharp edges,
2030 3 - solid connection,
2031 4 - 45 degree fingers with rounded corners,
2032 5 - horizontal & vertical fingers with rounded corners.
2034 Pins and Vias may have thermals whether or not there is a polygon available
2035 to connect with. However, they will have no effect without the polygon.
2039 ActionSetThermal (int argc
, char **argv
, Coord x
, Coord y
)
2041 char *function
= ARG (0);
2042 char *style
= ARG (1);
2043 void *ptr1
, *ptr2
, *ptr3
;
2047 if (function
&& *function
&& style
&& *style
)
2051 kind
= GetValue (style
, NULL
, &absolute
);
2053 switch (GetFunctionID (function
))
2057 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGETHERMAL_TYPES
,
2058 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
2060 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, kind
);
2061 IncrementUndoSerialNumber ();
2065 case F_SelectedPins
:
2066 ChangeSelectedThermals (PIN_TYPE
, kind
);
2068 case F_SelectedVias
:
2069 ChangeSelectedThermals (VIA_TYPE
, kind
);
2072 case F_SelectedElements
:
2073 ChangeSelectedThermals (CHANGETHERMAL_TYPES
, kind
);
2088 /* ---------------------------------------------------------------------------
2089 * !!! no action routine !!!
2091 * event handler to set the cursor according to the X pointer position
2092 * called from inside main.c
2095 EventMoveCrosshair (int ev_x
, int ev_y
)
2097 #ifdef HAVE_LIBSTROKE
2100 StrokeBox
.X2
= ev_x
;
2101 StrokeBox
.Y2
= ev_y
;
2102 stroke_record (ev_x
, ev_y
);
2105 #endif /* HAVE_LIBSTROKE */
2106 if (MoveCrosshairAbsolute (ev_x
, ev_y
))
2108 /* update object position and cursor location */
2109 AdjustAttachedObjects ();
2110 notify_crosshair_change (true);
2114 /* --------------------------------------------------------------------------- */
2116 static const char setvalue_syntax
[] =
2117 "SetValue(Grid|Line|LineSize|Text|TextScale|ViaDrillingHole|Via|ViaSize, delta)";
2119 static const char setvalue_help
[] =
2120 "Change various board-wide values and sizes.";
2122 /* %start-doc actions SetValue
2126 @item ViaDrillingHole
2127 Changes the diameter of the drill for new vias.
2130 Sets the grid spacing.
2134 Changes the thickness of new lines.
2138 Changes the diameter of new vias.
2142 Changes the size of new text.
2149 ActionSetValue (int argc
, char **argv
, Coord x
, Coord y
)
2151 char *function
= ARG (0);
2152 char *val
= ARG (1);
2153 char *units
= ARG (2);
2154 bool absolute
; /* flag for 'absolute' value */
2159 if (function
&& val
)
2161 value
= GetValue (val
, units
, &absolute
);
2162 switch (GetFunctionID (function
))
2164 case F_ViaDrillingHole
:
2165 SetViaDrillingHole (absolute
? value
:
2166 value
+ Settings
.ViaDrillingHole
,
2168 hid_action ("RouteStylesChanged");
2173 SetGrid (value
, false);
2177 value
= val
[0] == '-' ? -Settings
.increments
->grid
2178 : Settings
.increments
->grid
;
2179 /* On the way down, short against the minimum
2180 * PCB drawing unit */
2181 if ((value
+ PCB
->Grid
) < 1)
2183 else if (PCB
->Grid
== 1)
2184 SetGrid (value
, false);
2186 SetGrid (value
+ PCB
->Grid
, false);
2192 if (!absolute
&& value
== 0)
2193 value
= val
[0] == '-' ? -Settings
.increments
->line
2194 : Settings
.increments
->line
;
2195 SetLineSize (absolute
? value
: value
+ Settings
.LineThickness
);
2196 hid_action ("RouteStylesChanged");
2201 SetViaSize (absolute
? value
: value
+ Settings
.ViaThickness
, false);
2202 hid_action ("RouteStylesChanged");
2207 text_scale
= value
/ (double)FONT_CAPHEIGHT
* 100.;
2209 text_scale
+= Settings
.TextScale
;
2210 SetTextScale (text_scale
);
2224 /* --------------------------------------------------------------------------- */
2226 static const char quit_syntax
[] = "Quit()";
2228 static const char quit_help
[] = "Quits the application after confirming.";
2230 /* %start-doc actions Quit
2232 If you have unsaved changes, you will be prompted to confirm (or
2233 save) before quitting.
2238 ActionQuit (int argc
, char **argv
, Coord x
, Coord y
)
2240 char *force
= ARG (0);
2241 if (force
&& strcasecmp (force
, "force") == 0)
2246 if (!PCB
->Changed
|| gui
->close_confirm_dialog () == HID_CLOSE_CONFIRM_OK
)
2251 /* --------------------------------------------------------------------------- */
2253 static const char connection_syntax
[] =
2254 "Connection(Find|ResetLinesAndPolygons|ResetPinsAndVias|Reset)";
2256 static const char connection_help
[] =
2257 "Searches connections of the object at the cursor position.";
2259 /* %start-doc actions Connection
2261 Connections found with this action will be highlighted in the
2262 ``connected-color'' color and will have the ``found'' flag set.
2267 The net under the cursor is ``found''.
2269 @item ResetLinesAndPolygons
2270 Any ``found'' lines and polygons are marked ``not found''.
2272 @item ResetPinsAndVias
2273 Any ``found'' pins and vias are marked ``not found''.
2276 All ``found'' objects are marked ``not found''.
2283 ActionConnection (int argc
, char **argv
, Coord x
, Coord y
)
2285 char *function
= ARG (0);
2288 switch (GetFunctionID (function
))
2292 gui
->get_coords (_("Click on a connection"), &x
, &y
);
2293 LookupConnection (x
, y
, true, 1, FOUNDFLAG
, false);
2297 case F_ResetLinesAndPolygons
:
2298 if (ResetFoundLinesAndPolygons (true, FOUNDFLAG
))
2300 IncrementUndoSerialNumber ();
2305 case F_ResetPinsViasAndPads
:
2306 if (ResetFoundPinsViasAndPads (true, FOUNDFLAG
))
2308 IncrementUndoSerialNumber ();
2314 if (ResetConnections (true, FOUNDFLAG
))
2316 IncrementUndoSerialNumber ();
2327 /* --------------------------------------------------------------------------- */
2329 static const char disperseelements_syntax
[] =
2330 "DisperseElements(All|Selected)";
2332 static const char disperseelements_help
[] = "Disperses elements.";
2334 /* %start-doc actions DisperseElements
2336 Normally this is used when starting a board, by selecting all elements
2337 and then dispersing them. This scatters the elements around the board
2338 so that you can pick individual ones, rather than have all the
2339 elements at the same 0,0 coordinate and thus impossible to choose
2344 #define GAP MIL_TO_COORD(100)
2347 ActionDisperseElements (int argc
, char **argv
, Coord x
, Coord y
)
2349 char *function
= ARG (0);
2354 int all
= 0, bad
= 0;
2356 if (!function
|| !*function
)
2362 switch (GetFunctionID (function
))
2379 AFAIL (disperseelements
);
2383 ELEMENT_LOOP (PCB
->Data
);
2386 * If we want to disperse selected elements, maybe we need smarter
2387 * code here to avoid putting components on top of others which
2388 * are not selected. For now, I'm assuming that this is typically
2389 * going to be used either with a brand new design or a scratch
2390 * design holding some new components
2392 if (!TEST_FLAG (LOCKFLAG
, element
) && (all
|| TEST_FLAG (SELECTEDFLAG
, element
)))
2395 /* figure out how much to move the element */
2396 dx
= minx
- element
->BoundingBox
.X1
;
2398 /* snap to the grid */
2399 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2402 * and add one grid size so we make sure we always space by GAP or
2407 /* Figure out if this row has room. If not, start a new row */
2408 if (GAP
+ element
->BoundingBox
.X2
+ dx
> PCB
->MaxWidth
)
2414 /* figure out how much to move the element */
2415 dx
= minx
- element
->BoundingBox
.X1
;
2416 dy
= miny
- element
->BoundingBox
.Y1
;
2418 /* snap to the grid */
2419 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2421 dy
-= (element
->MarkY
+ dy
) % PCB
->Grid
;
2424 /* move the element */
2425 MoveElementLowLevel (PCB
->Data
, element
, dx
, dy
);
2427 /* and add to the undo list so we can undo this operation */
2428 AddObjectToMoveUndoList (ELEMENT_TYPE
, NULL
, NULL
, element
, dx
, dy
);
2430 /* keep track of how tall this row is */
2431 minx
+= element
->BoundingBox
.X2
- element
->BoundingBox
.X1
+ GAP
;
2432 if (maxy
< element
->BoundingBox
.Y2
)
2434 maxy
= element
->BoundingBox
.Y2
;
2441 /* done with our action so increment the undo # */
2442 IncrementUndoSerialNumber ();
2445 SetChangedFlag (true);
2452 /* --------------------------------------------------------------------------- */
2454 static const char display_syntax
[] =
2455 "Display(NameOnPCB|Description|Value)\n"
2456 "Display(Grid|Redraw)\n"
2457 "Display(CycleClip|CycleCrosshair|Toggle45Degree|ToggleStartDirection)\n"
2458 "Display(ToggleGrid|ToggleRubberBandMode|ToggleUniqueNames)\n"
2459 "Display(ToggleMask|ToggleName|ToggleClearLine|ToggleFullPoly|ToggleSnapPin)\n"
2460 "Display(ToggleThindraw|ToggleThindrawPoly|ToggleOrthoMove|ToggleLocalRef)\n"
2461 "Display(ToggleCheckPlanes|ToggleShowDRC|ToggleAutoDRC)\n"
2462 "Display(ToggleLiveRoute|LockNames|OnlyNames)\n"
2463 "Display(Pinout|PinOrPadName)";
2465 static const char display_help
[] = "Several display-related actions.";
2467 /* %start-doc actions Display
2474 Specify whether all elements show their name, description, or value.
2477 Redraw the whole board.
2479 @item Toggle45Degree
2480 When clear, lines can be drawn at any angle. When set, lines are
2481 restricted to multiples of 45 degrees and requested lines may be
2482 broken up according to the clip setting.
2485 Changes the way lines are restricted to 45 degree increments. The
2486 various settings are: straight only, orthogonal then angled, and angled
2487 then orthogonal. If AllDirections is set, this action disables it.
2489 @item CycleCrosshair
2490 Changes crosshair drawing. Crosshair may accept form of 4-ray,
2491 8-ray and 12-ray cross.
2493 @item ToggleRubberBandMode
2494 If set, moving an object moves all the lines attached to it too.
2496 @item ToggleStartDirection
2497 If set, each time you set a point in a line, the Clip toggles between
2498 orth-angle and angle-ortho.
2500 @item ToggleUniqueNames
2501 If set, you will not be permitted to change the name of an element to
2502 match that of another element.
2505 If set, pin centers and pad end points are treated as additional grid
2506 points that the cursor can snap to.
2508 @item ToggleLocalRef
2509 If set, the mark is automatically set to the beginning of any move, so
2510 you can see the relative distance you've moved.
2512 @item ToggleThindraw
2513 If set, objects on the screen are drawn as outlines (lines are drawn
2514 as center-lines). This lets you see line endpoints hidden under pins,
2517 @item ToggleThindrawPoly
2518 If set, polygons on the screen are drawn as outlines.
2521 If set, pending objects (i.e. lines you're in the process of drawing)
2522 will be drawn with an outline showing how far away from other copper
2525 @item ToggleLiveRoute
2526 If set, the progress of the autorouter will be visible on the screen.
2529 If set, you will not be permitted to make connections which violate
2530 the current DRC and netlist settings.
2532 @item ToggleCheckPlanes
2533 If set, lines and arcs aren't drawn, which usually leaves just the
2534 polygons. If you also disable all but the layer you're interested in,
2535 this allows you to check for isolated regions.
2537 @item ToggleOrthoMove
2538 If set, the crosshair is only allowed to move orthogonally from its
2539 previous position. I.e. you can move an element or line up, down,
2540 left, or right, but not up+left or down+right.
2543 Selects whether the pinouts show the pin names or the pin numbers.
2545 @item ToggleLockNames
2546 If set, text will ignore left mouse clicks and actions that work on
2547 objects under the mouse. You can still select text with a lasso (left
2548 mouse drag) and perform actions on the selection.
2550 @item ToggleOnlyNames
2551 If set, only text will be sensitive for mouse clicks and actions that
2552 work on objects under the mouse. You can still select other objects
2553 with a lasso (left mouse drag) and perform actions on the selection.
2556 Turns the solder mask on or off.
2558 @item ToggleClearLine
2559 When set, the clear-line flag causes new lines and arcs to have their
2560 ``clear polygons'' flag set, so they won't be electrically connected
2561 to any polygons they overlap.
2563 @item ToggleFullPoly
2564 When set, the full-poly flag causes new polygons to have their
2565 ``full polygon'' flag set, so all parts of them will be displayed
2566 instead of only the biggest one.
2569 Resets the origin of the current grid to be wherever the mouse pointer
2570 is (not where the crosshair currently is). If you provide two numbers
2571 after this, the origin is set to that coordinate.
2574 Toggles whether the grid is displayed or not.
2577 Causes the pinout of the element indicated by the cursor to be
2578 displayed, usually in a separate window.
2581 Toggles whether the names of pins, pads, or (yes) vias will be
2582 displayed. If the cursor is over an element, all of its pins and pads
2589 static enum crosshair_shape
2590 CrosshairShapeIncrement (enum crosshair_shape shape
)
2594 case Basic_Crosshair_Shape
:
2595 shape
= Union_Jack_Crosshair_Shape
;
2597 case Union_Jack_Crosshair_Shape
:
2598 shape
= Dozen_Crosshair_Shape
;
2600 case Dozen_Crosshair_Shape
:
2601 shape
= Crosshair_Shapes_Number
;
2603 case Crosshair_Shapes_Number
:
2604 shape
= Basic_Crosshair_Shape
;
2611 ActionDisplay (int argc
, char **argv
, Coord childX
, Coord childY
)
2613 char *function
, *str_dir
;
2620 if (function
&& (!str_dir
|| !*str_dir
))
2622 switch (id
= GetFunctionID (function
))
2626 case F_ClearAndRedraw
:
2631 /* change the displayed name of elements */
2635 ELEMENT_LOOP (PCB
->Data
);
2637 EraseElementName (element
);
2640 CLEAR_FLAG (DESCRIPTIONFLAG
| NAMEONPCBFLAG
, PCB
);
2646 SET_FLAG (NAMEONPCBFLAG
, PCB
);
2649 SET_FLAG (DESCRIPTIONFLAG
, PCB
);
2652 ELEMENT_LOOP (PCB
->Data
);
2654 DrawElementName (element
);
2660 /* toggle line-adjust flag */
2661 case F_ToggleAllDirections
:
2662 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2663 AdjustAttachedObjects ();
2667 notify_crosshair_change (false);
2668 if (TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
2670 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2674 PCB
->Clipping
= (PCB
->Clipping
+ 1) % 3;
2675 AdjustAttachedObjects ();
2676 notify_crosshair_change (true);
2679 case F_CycleCrosshair
:
2680 notify_crosshair_change (false);
2681 Crosshair
.shape
= CrosshairShapeIncrement(Crosshair
.shape
);
2682 if (Crosshair_Shapes_Number
== Crosshair
.shape
)
2683 Crosshair
.shape
= Basic_Crosshair_Shape
;
2684 notify_crosshair_change (true);
2687 case F_ToggleRubberBandMode
:
2688 notify_crosshair_change (false);
2689 TOGGLE_FLAG (RUBBERBANDFLAG
, PCB
);
2690 notify_crosshair_change (true);
2693 case F_ToggleStartDirection
:
2694 notify_crosshair_change (false);
2695 TOGGLE_FLAG (SWAPSTARTDIRFLAG
, PCB
);
2696 notify_crosshair_change (true);
2699 case F_ToggleUniqueNames
:
2700 TOGGLE_FLAG (UNIQUENAMEFLAG
, PCB
);
2703 case F_ToggleSnapPin
:
2704 notify_crosshair_change (false);
2705 TOGGLE_FLAG (SNAPPINFLAG
, PCB
);
2706 notify_crosshair_change (true);
2709 case F_ToggleLocalRef
:
2710 TOGGLE_FLAG (LOCALREFFLAG
, PCB
);
2713 case F_ToggleThindraw
:
2714 TOGGLE_FLAG (THINDRAWFLAG
, PCB
);
2718 case F_ToggleThindrawPoly
:
2719 TOGGLE_FLAG (THINDRAWPOLYFLAG
, PCB
);
2723 case F_ToggleLockNames
:
2724 TOGGLE_FLAG (LOCKNAMESFLAG
, PCB
);
2725 CLEAR_FLAG (ONLYNAMESFLAG
, PCB
);
2728 case F_ToggleOnlyNames
:
2729 TOGGLE_FLAG (ONLYNAMESFLAG
, PCB
);
2730 CLEAR_FLAG (LOCKNAMESFLAG
, PCB
);
2733 case F_ToggleHideNames
:
2734 TOGGLE_FLAG (HIDENAMESFLAG
, PCB
);
2738 case F_ToggleShowDRC
:
2739 TOGGLE_FLAG (SHOWDRCFLAG
, PCB
);
2742 case F_ToggleLiveRoute
:
2743 TOGGLE_FLAG (LIVEROUTEFLAG
, PCB
);
2746 case F_ToggleAutoDRC
:
2747 notify_crosshair_change (false);
2748 TOGGLE_FLAG (AUTODRCFLAG
, PCB
);
2749 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
2751 if (ResetConnections (true, FOUNDFLAG
))
2753 IncrementUndoSerialNumber ();
2756 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
2757 LookupConnection (Crosshair
.AttachedLine
.Point1
.X
,
2758 Crosshair
.AttachedLine
.Point1
.Y
, true, 1,
2761 notify_crosshair_change (true);
2764 case F_ToggleCheckPlanes
:
2765 TOGGLE_FLAG (CHECKPLANESFLAG
, PCB
);
2769 case F_ToggleOrthoMove
:
2770 TOGGLE_FLAG (ORTHOMOVEFLAG
, PCB
);
2774 TOGGLE_FLAG (SHOWNUMBERFLAG
, PCB
);
2779 TOGGLE_FLAG (SHOWMASKFLAG
, PCB
);
2783 case F_ToggleClearLine
:
2784 TOGGLE_FLAG (CLEARNEWFLAG
, PCB
);
2787 case F_ToggleFullPoly
:
2788 TOGGLE_FLAG (NEWFULLPOLYFLAG
, PCB
);
2791 /* shift grid alignment */
2794 Coord oldGrid
= PCB
->Grid
;
2797 if (MoveCrosshairAbsolute (Crosshair
.X
, Crosshair
.Y
))
2798 notify_crosshair_change (true); /* first notify was in MoveCrosshairAbs */
2799 SetGrid (oldGrid
, true);
2803 /* toggle displaying of the grid */
2805 Settings
.DrawGrid
= !Settings
.DrawGrid
;
2809 /* display the pinout of an element */
2812 ElementType
*element
;
2816 gui
->get_coords (_("Click on an element"), &x
, &y
);
2818 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
2819 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
2821 element
= (ElementType
*) ptrtmp
;
2822 gui
->show_item (element
);
2827 /* toggle displaying of pin/pad/via names */
2828 case F_PinOrPadName
:
2830 void *ptr1
, *ptr2
, *ptr3
;
2832 switch (SearchScreen (Crosshair
.X
, Crosshair
.Y
,
2833 ELEMENT_TYPE
| PIN_TYPE
| PAD_TYPE
|
2834 VIA_TYPE
, (void **) &ptr1
, (void **) &ptr2
,
2838 PIN_LOOP ((ElementType
*) ptr1
);
2840 if (TEST_FLAG (DISPLAYNAMEFLAG
, pin
))
2844 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, pin
, pin
);
2845 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pin
);
2848 PAD_LOOP ((ElementType
*) ptr1
);
2850 if (TEST_FLAG (DISPLAYNAMEFLAG
, pad
))
2854 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, pad
, pad
);
2855 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pad
);
2858 SetChangedFlag (true);
2859 IncrementUndoSerialNumber ();
2864 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
))
2865 ErasePinName ((PinType
*) ptr2
);
2867 DrawPinName ((PinType
*) ptr2
);
2868 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, ptr2
, ptr3
);
2869 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
);
2870 SetChangedFlag (true);
2871 IncrementUndoSerialNumber ();
2876 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PadType
*) ptr2
))
2877 ErasePadName ((PadType
*) ptr2
);
2879 DrawPadName ((PadType
*) ptr2
);
2880 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, ptr2
, ptr3
);
2881 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PadType
*) ptr2
);
2882 SetChangedFlag (true);
2883 IncrementUndoSerialNumber ();
2887 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
))
2888 EraseViaName ((PinType
*) ptr2
);
2890 DrawViaName ((PinType
*) ptr2
);
2891 AddObjectToFlagUndoList (VIA_TYPE
, ptr1
, ptr2
, ptr3
);
2892 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
);
2893 SetChangedFlag (true);
2894 IncrementUndoSerialNumber ();
2904 else if (function
&& str_dir
)
2906 switch (GetFunctionID (function
))
2911 PCB
->GridOffsetX
= GetValue (argv
[1], NULL
, NULL
);
2912 PCB
->GridOffsetY
= GetValue (argv
[2], NULL
, NULL
);
2913 if (Settings
.DrawGrid
)
2930 /* --------------------------------------------------------------------------- */
2932 static const char mode_syntax
[] =
2933 "Mode(Arc|Arrow|Copy|InsertPoint|Line|Lock|Move|None|PasteBuffer)\n"
2934 "Mode(Polygon|Rectangle|Remove|Rotate|Text|Thermal|Via)\n"
2935 "Mode(Notify|Release|Cancel|Stroke)\n"
2936 "Mode(Save|Restore)";
2938 static const char mode_help
[] = "Change or use the tool mode.";
2940 /* %start-doc actions Mode
2960 Select the indicated tool.
2963 Called when you press the mouse button, or move the mouse.
2966 Called when you release the mouse button.
2969 Cancels any pending tool activity, allowing you to restart elsewhere.
2970 For example, this allows you to start a new line rather than attach a
2971 line to the previous line.
2974 Similar to Cancel but calling this action a second time will return
2978 If your @code{pcb} was built with libstroke, this invokes the stroke
2979 input method. If not, this will restart a drawing mode if you were
2980 drawing, else it will select objects.
2983 Remembers the current tool.
2986 Restores the tool to the last saved tool.
2993 ActionMode (int argc
, char **argv
, Coord x
, Coord y
)
2995 char *function
= ARG (0);
2999 Note
.X
= Crosshair
.X
;
3000 Note
.Y
= Crosshair
.Y
;
3001 notify_crosshair_change (false);
3002 switch (GetFunctionID (function
))
3008 SetMode (ARROW_MODE
);
3011 SetMode (COPY_MODE
);
3014 SetMode (INSERTPOINT_MODE
);
3017 SetMode (LINE_MODE
);
3020 SetMode (LOCK_MODE
);
3023 SetMode (MOVE_MODE
);
3030 int saved_mode
= Settings
.Mode
;
3032 SetMode (saved_mode
);
3037 switch (Settings
.Mode
)
3040 case PASTEBUFFER_MODE
:
3046 case INSERTPOINT_MODE
:
3047 case RUBBERBANDMOVE_MODE
:
3051 SetMode (ARROW_MODE
);
3055 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3056 SetMode (ARROW_MODE
);
3060 SetMode (LINE_MODE
);
3064 case RECTANGLE_MODE
:
3065 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3066 SetMode (ARROW_MODE
);
3070 SetMode (RECTANGLE_MODE
);
3075 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3076 SetMode (ARROW_MODE
);
3080 SetMode (POLYGON_MODE
);
3084 case POLYGONHOLE_MODE
:
3085 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3086 SetMode (ARROW_MODE
);
3090 SetMode (POLYGONHOLE_MODE
);
3095 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3096 SetMode (ARROW_MODE
);
3117 SetMode (PASTEBUFFER_MODE
);
3120 SetMode (POLYGON_MODE
);
3123 SetMode (POLYGONHOLE_MODE
);
3125 #ifndef HAVE_LIBSTROKE
3138 SetMode (REMOVE_MODE
);
3141 SetMode (RECTANGLE_MODE
);
3144 SetMode (ROTATE_MODE
);
3147 #ifdef HAVE_LIBSTROKE
3149 StrokeBox
.X1
= Crosshair
.X
;
3150 StrokeBox
.Y1
= Crosshair
.Y
;
3153 /* Handle middle mouse button restarts of drawing mode. If not in
3154 | a drawing mode, middle mouse button will select objects.
3156 if (Settings
.Mode
== LINE_MODE
3157 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3159 SetMode (LINE_MODE
);
3161 else if (Settings
.Mode
== ARC_MODE
3162 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3164 else if (Settings
.Mode
== RECTANGLE_MODE
3165 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3166 SetMode (RECTANGLE_MODE
);
3167 else if (Settings
.Mode
== POLYGON_MODE
3168 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3169 SetMode (POLYGON_MODE
);
3174 SetMode (ARROW_MODE
);
3180 SetMode (TEXT_MODE
);
3183 SetMode (THERMAL_MODE
);
3189 case F_Restore
: /* restore the last saved mode */
3193 case F_Save
: /* save currently selected mode */
3197 notify_crosshair_change (true);
3204 /* --------------------------------------------------------------------------- */
3206 static const char removeselected_syntax
[] = "RemoveSelected()";
3208 static const char removeselected_help
[] = "Removes any selected objects.";
3210 /* %start-doc actions RemoveSelected
3215 ActionRemoveSelected (int argc
, char **argv
, Coord x
, Coord y
)
3217 if (RemoveSelected ())
3218 SetChangedFlag (true);
3222 /* --------------------------------------------------------------------------- */
3224 static const char renumber_syntax
[] = "Renumber()\n"
3225 "Renumber(filename)";
3227 static const char renumber_help
[] =
3228 "Renumber all elements. The changes will be recorded to filename\n"
3229 "for use in backannotating these changes to the schematic.";
3231 /* %start-doc actions Renumber
3236 ActionRenumber (int argc
, char **argv
, Coord x
, Coord y
)
3238 bool changed
= false;
3239 ElementType
**element_list
;
3240 ElementType
**locked_element_list
;
3241 unsigned int i
, j
, k
, cnt
, lock_cnt
;
3247 static char * default_file
= NULL
;
3248 size_t cnt_list_sz
= 100;
3254 char **was
, **is
, *pin
;
3255 unsigned int c_cnt
= 0;
3262 * We deal with the case where name already exists in this
3263 * function so the GUI doesn't need to deal with it
3265 name
= gui
->fileselect (_("Save Renumber Annotation File As ..."),
3266 _("Choose a file to record the renumbering to.\n"
3267 "This file may be used to back annotate the\n"
3268 "change to the schematics.\n"),
3269 default_file
, ".eco", "eco",
3279 free (default_file
);
3280 default_file
= NULL
;
3285 default_file
= strdup (name
);
3288 if ((out
= fopen (name
, "r")))
3291 if (!gui
->confirm_dialog (_("File exists! Ok to overwrite?"), 0))
3293 if (free_name
&& name
)
3299 if ((out
= fopen (name
, "w")) == NULL
)
3301 Message (_("Could not open %s\n"), name
);
3302 if (free_name
&& name
)
3307 if (free_name
&& name
)
3310 fprintf (out
, "*COMMENT* PCB Annotation File\n");
3311 fprintf (out
, "*FILEVERSION* 20061031\n");
3314 * Make a first pass through all of the elements and sort them out
3315 * by location on the board. While here we also collect a list of
3318 * We'll actually renumber things in the 2nd pass.
3320 element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementType
*));
3321 locked_element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementType
*));
3322 was
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3323 is
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3324 if (element_list
== NULL
|| locked_element_list
== NULL
|| was
== NULL
3327 fprintf (stderr
, "calloc() failed in %s\n", __FUNCTION__
);
3334 ELEMENT_LOOP (PCB
->Data
);
3336 if (TEST_FLAG (LOCKFLAG
, element
->Name
) || TEST_FLAG (LOCKFLAG
, element
))
3339 * add to the list of locked elements which we won't try to
3340 * renumber and whose reference designators are now reserved.
3343 "*WARN* Element \"%s\" at %$md is locked and will not be renumbered.\n",
3344 UNKNOWN (NAMEONPCB_NAME (element
)), element
->MarkX
, element
->MarkY
);
3345 locked_element_list
[lock_cnt
] = element
;
3351 /* count of devices which will be renumbered */
3354 /* search for correct position in the list */
3356 while (element_list
[i
] && element
->MarkY
> element_list
[i
]->MarkY
)
3360 * We have found the position where we have the first element that
3361 * has the same Y value or a lower Y value. Now move forward if
3362 * needed through the X values
3364 while (element_list
[i
]
3365 && element
->MarkY
== element_list
[i
]->MarkY
3366 && element
->MarkX
> element_list
[i
]->MarkX
)
3369 for (j
= cnt
- 1; j
> i
; j
--)
3371 element_list
[j
] = element_list
[j
- 1];
3373 element_list
[i
] = element
;
3380 * Now that the elements are sorted by board position, we go through
3381 * and renumber them.
3385 * turn off the flag which requires unique names so it doesn't get
3386 * in our way. When we're done with the renumber we will have unique
3389 unique
= TEST_FLAG (UNIQUENAMEFLAG
, PCB
);
3390 CLEAR_FLAG (UNIQUENAMEFLAG
, PCB
);
3392 cnt_list
= (struct _cnt_list
*)calloc (cnt_list_sz
, sizeof (struct _cnt_list
));
3393 for (i
= 0; i
< cnt
; i
++)
3395 /* If there is no refdes, maybe just spit out a warning */
3396 if (NAMEONPCB_NAME (element_list
[i
]))
3398 /* figure out the prefix */
3399 tmps
= strdup (NAMEONPCB_NAME (element_list
[i
]));
3401 while (tmps
[j
] && (tmps
[j
] < '0' || tmps
[j
] > '9')
3406 /* check the counter for this prefix */
3408 cnt_list
[j
].name
&& (strcmp (cnt_list
[j
].name
, tmps
) != 0)
3409 && j
< cnt_list_sz
; j
++);
3411 /* grow the list if needed */
3412 if (j
== cnt_list_sz
)
3415 cnt_list
= (struct _cnt_list
*)realloc (cnt_list
, cnt_list_sz
);
3416 if (cnt_list
== NULL
)
3418 fprintf (stderr
, "realloc failed() in %s\n", __FUNCTION__
);
3421 /* zero out the memory that we added */
3422 for (tmpi
= j
; tmpi
< cnt_list_sz
; tmpi
++)
3424 cnt_list
[tmpi
].name
= NULL
;
3425 cnt_list
[tmpi
].cnt
= 0;
3430 * start a new counter if we don't have a counter for this
3433 if (!cnt_list
[j
].name
)
3435 cnt_list
[j
].name
= strdup (tmps
);
3436 cnt_list
[j
].cnt
= 0;
3440 * check to see if the new refdes is already used by a
3449 /* space for the prefix plus 1 digit plus the '\0' */
3450 sz
= strlen (cnt_list
[j
].name
) + 2;
3452 /* and 1 more per extra digit needed to hold the number */
3453 tmpi
= cnt_list
[j
].cnt
;
3459 tmps
= (char *)malloc (sz
* sizeof (char));
3460 sprintf (tmps
, "%s%d", cnt_list
[j
].name
, cnt_list
[j
].cnt
);
3463 * now compare to the list of reserved (by locked
3466 for (k
= 0; k
< lock_cnt
; k
++)
3469 (UNKNOWN (NAMEONPCB_NAME (locked_element_list
[k
])),
3480 if (strcmp (tmps
, NAMEONPCB_NAME (element_list
[i
])) != 0)
3482 fprintf (out
, "*RENAME* \"%s\" \"%s\"\n",
3483 NAMEONPCB_NAME (element_list
[i
]), tmps
);
3485 /* add this rename to our table of renames so we can update the netlist */
3486 was
[c_cnt
] = strdup (NAMEONPCB_NAME (element_list
[i
]));
3487 is
[c_cnt
] = strdup (tmps
);
3490 AddObjectToChangeNameUndoList (ELEMENT_TYPE
, NULL
, NULL
,
3492 NAMEONPCB_NAME (element_list
3495 ChangeObjectName (ELEMENT_TYPE
, element_list
[i
], NULL
, NULL
,
3499 /* we don't free tmps in this case because it is used */
3506 pcb_fprintf (out
, "*WARN* Element at %$md has no name.\n",
3507 element_list
[i
]->MarkX
, element_list
[i
]->MarkY
);
3514 /* restore the unique flag setting */
3516 SET_FLAG (UNIQUENAMEFLAG
, PCB
);
3521 /* update the netlist */
3522 AddNetlistLibToUndoList (&(PCB
->NetlistLib
));
3524 /* iterate over each net */
3525 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
3528 /* iterate over each pin on the net */
3529 for (j
= 0; j
< PCB
->NetlistLib
.Menu
[i
].EntryN
; j
++)
3532 /* figure out the pin number part from strings like U3-21 */
3533 tmps
= strdup (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3534 for (k
= 0; tmps
[k
] && tmps
[k
] != '-'; k
++);
3538 /* iterate over the list of changed reference designators */
3539 for (k
= 0; k
< c_cnt
; k
++)
3542 * if the pin needs to change, change it and quit
3543 * searching in the list.
3545 if (strcmp (tmps
, was
[k
]) == 0)
3547 free (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3548 PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
=
3549 (char *)malloc ((strlen (is
[k
]) + strlen (pin
) +
3550 2) * sizeof (char));
3551 sprintf (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
,
3552 "%s-%s", is
[k
], pin
);
3560 for (k
= 0; k
< c_cnt
; k
++)
3567 IncrementUndoSerialNumber ();
3568 SetChangedFlag (true);
3571 free (locked_element_list
);
3572 free (element_list
);
3578 /* --------------------------------------------------------------------------- */
3580 static const char ripup_syntax
[] = "RipUp(All|Selected|Element)";
3582 static const char ripup_help
[] =
3583 "Ripup auto-routed tracks, or convert an element to parts.";
3585 /* %start-doc actions RipUp
3590 Removes all lines and vias which were created by the autorouter.
3593 Removes all selected lines and vias which were created by the
3597 Converts the element under the cursor to parts (vias and lines). Note
3598 that this uses the highest numbered paste buffer.
3605 ActionRipUp (int argc
, char **argv
, Coord x
, Coord y
)
3607 char *function
= ARG (0);
3608 bool changed
= false;
3612 switch (GetFunctionID (function
))
3615 ALLLINE_LOOP (PCB
->Data
);
3617 if (TEST_FLAG (AUTOFLAG
, line
) && !TEST_FLAG (LOCKFLAG
, line
))
3619 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3624 ALLARC_LOOP (PCB
->Data
);
3626 if (TEST_FLAG (AUTOFLAG
, arc
) && !TEST_FLAG (LOCKFLAG
, arc
))
3628 RemoveObject (ARC_TYPE
, layer
, arc
, arc
);
3633 VIA_LOOP (PCB
->Data
);
3635 if (TEST_FLAG (AUTOFLAG
, via
) && !TEST_FLAG (LOCKFLAG
, via
))
3637 RemoveObject (VIA_TYPE
, via
, via
, via
);
3645 IncrementUndoSerialNumber ();
3646 SetChangedFlag (true);
3650 VISIBLELINE_LOOP (PCB
->Data
);
3652 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, line
)
3653 && !TEST_FLAG (LOCKFLAG
, line
))
3655 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3661 VIA_LOOP (PCB
->Data
);
3663 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, via
)
3664 && !TEST_FLAG (LOCKFLAG
, via
))
3666 RemoveObject (VIA_TYPE
, via
, via
, via
);
3673 IncrementUndoSerialNumber ();
3674 SetChangedFlag (true);
3679 void *ptr1
, *ptr2
, *ptr3
;
3681 if (SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
3682 &ptr1
, &ptr2
, &ptr3
) != NO_TYPE
)
3684 Note
.Buffer
= Settings
.BufferNumber
;
3685 SetBufferNumber (MAX_BUFFER
- 1);
3686 ClearBuffer (PASTEBUFFER
);
3687 CopyObjectToBuffer (PASTEBUFFER
->Data
, PCB
->Data
,
3688 ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3689 SmashBufferElement (PASTEBUFFER
);
3692 SaveUndoSerialNumber ();
3693 EraseObject (ELEMENT_TYPE
, ptr1
, ptr1
);
3694 MoveObjectToRemoveUndoList (ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3695 RestoreUndoSerialNumber ();
3696 CopyPastebufferToLayout (0, 0);
3697 SetBufferNumber (Note
.Buffer
);
3698 SetChangedFlag (true);
3707 /* --------------------------------------------------------------------------- */
3709 static const char addrats_syntax
[] = "AddRats(AllRats|SelectedRats|Close)";
3711 static const char addrats_help
[] = "Add one or more rat lines to the board.";
3713 /* %start-doc actions AddRats
3718 Create rat lines for all loaded nets that aren't already connected on
3722 Similarly, but only add rat lines for nets connected to selected pins
3726 Selects the shortest unselected rat on the board.
3733 ActionAddRats (int argc
, char **argv
, Coord x
, Coord y
)
3735 char *function
= ARG (0);
3741 if (Settings
.RatWarn
)
3743 switch (GetFunctionID (function
))
3746 if (AddAllRats (false, NULL
))
3747 SetChangedFlag (true);
3749 case F_SelectedRats
:
3751 if (AddAllRats (true, NULL
))
3752 SetChangedFlag (true);
3755 small
= SQUARE (MAX_COORD
);
3757 RAT_LOOP (PCB
->Data
);
3759 if (TEST_FLAG (SELECTEDFLAG
, line
))
3761 len
= SQUARE (line
->Point1
.X
- line
->Point2
.X
) +
3762 SQUARE (line
->Point1
.Y
- line
->Point2
.Y
);
3772 AddObjectToFlagUndoList (RATLINE_TYPE
, shorty
, shorty
, shorty
);
3773 SET_FLAG (SELECTEDFLAG
, shorty
);
3776 CenterDisplay ((shorty
->Point2
.X
+ shorty
->Point1
.X
) / 2,
3777 (shorty
->Point2
.Y
+ shorty
->Point1
.Y
) / 2);
3785 /* --------------------------------------------------------------------------- */
3787 static const char delete_syntax
[] =
3788 "Delete(Object|Selected)\n"
3789 "Delete(AllRats|SelectedRats)";
3791 static const char delete_help
[] = "Delete stuff.";
3793 /* %start-doc actions Delete
3798 ActionDelete (int argc
, char **argv
, Coord x
, Coord y
)
3800 char *function
= ARG (0);
3801 int id
= GetFunctionID (function
);
3803 Note
.X
= Crosshair
.X
;
3804 Note
.Y
= Crosshair
.Y
;
3806 if (id
== -1) /* no arg */
3808 if (RemoveSelected() == false)
3816 SetMode(REMOVE_MODE
);
3824 if (DeleteRats (false))
3825 SetChangedFlag (true);
3827 case F_SelectedRats
:
3828 if (DeleteRats (true))
3829 SetChangedFlag (true);
3836 /* --------------------------------------------------------------------------- */
3838 static const char deleterats_syntax
[] =
3839 "DeleteRats(AllRats|Selected|SelectedRats)";
3841 static const char deleterats_help
[] = "Delete rat lines.";
3843 /* %start-doc actions DeleteRats
3848 ActionDeleteRats (int argc
, char **argv
, Coord x
, Coord y
)
3850 char *function
= ARG (0);
3853 if (Settings
.RatWarn
)
3855 switch (GetFunctionID (function
))
3858 if (DeleteRats (false))
3859 SetChangedFlag (true);
3861 case F_SelectedRats
:
3863 if (DeleteRats (true))
3864 SetChangedFlag (true);
3871 /* --------------------------------------------------------------------------- */
3873 static const char autoplace_syntax
[] = "AutoPlaceSelected()";
3875 static const char autoplace_help
[] = "Auto-place selected components.";
3877 /* %start-doc actions AutoPlaceSelected
3879 Attempts to re-arrange the selected components such that the nets
3880 connecting them are minimized. Note that you cannot undo this.
3885 ActionAutoPlaceSelected (int argc
, char **argv
, Coord x
, Coord y
)
3888 if (gui
->confirm_dialog (_("Auto-placement can NOT be undone.\n"
3889 "Do you want to continue anyway?\n"), 0))
3891 if (AutoPlaceSelected ())
3892 SetChangedFlag (true);
3897 /* --------------------------------------------------------------------------- */
3899 static const char autoroute_syntax
[] = "AutoRoute(AllRats|SelectedRats)";
3901 static const char autoroute_help
[] = "Auto-route some or all rat lines.";
3903 /* %start-doc actions AutoRoute
3908 Attempt to autoroute all rats.
3911 Attempt to autoroute the selected rats.
3915 Before autorouting, it's important to set up a few things. First,
3916 make sure any layers you aren't using are disabled, else the
3917 autorouter may use them. Next, make sure the current line and via
3918 styles are set accordingly. Last, make sure "new lines clear
3919 polygons" is set, in case you eventually want to add a copper pour.
3921 Autorouting takes a while. During this time, the program may not be
3927 ActionAutoRoute (int argc
, char **argv
, Coord x
, Coord y
)
3929 char *function
= ARG (0);
3931 if (function
) /* one parameter */
3933 switch (GetFunctionID (function
))
3936 if (AutoRoute (false))
3937 SetChangedFlag (true);
3939 case F_SelectedRats
:
3941 if (AutoRoute (true))
3942 SetChangedFlag (true);
3949 /* --------------------------------------------------------------------------- */
3951 static const char markcrosshair_syntax
[] =
3953 "MarkCrosshair(Center)";
3955 static const char markcrosshair_help
[] = "Set/Reset the Crosshair mark.";
3957 /* %start-doc actions MarkCrosshair
3959 The ``mark'' is a small X-shaped target on the display which is
3960 treated like a second origin (the normal origin is the upper let
3961 corner of the board). The GUI will display a second set of
3962 coordinates for this mark, which tells you how far you are from it.
3964 If no argument is given, the mark is toggled - disabled if it was
3965 enabled, or enabled at the current cursor position of disabled. If
3966 the @code{Center} argument is given, the mark is moved to the current
3972 ActionMarkCrosshair (int argc
, char **argv
, Coord x
, Coord y
)
3974 char *function
= ARG (0);
3975 if (!function
|| !*function
)
3979 notify_mark_change (false);
3980 Marked
.status
= false;
3981 notify_mark_change (true);
3985 notify_mark_change (false);
3986 Marked
.status
= false;
3987 Marked
.status
= true;
3988 Marked
.X
= Crosshair
.X
;
3989 Marked
.Y
= Crosshair
.Y
;
3990 notify_mark_change (true);
3993 else if (GetFunctionID (function
) == F_Center
)
3995 notify_mark_change (false);
3996 Marked
.status
= true;
3997 Marked
.X
= Crosshair
.X
;
3998 Marked
.Y
= Crosshair
.Y
;
3999 notify_mark_change (true);
4004 /* --------------------------------------------------------------------------- */
4006 static const char changesize_syntax
[] =
4007 "ChangeSize(Object, delta)\n"
4008 "ChangeSize(SelectedObjects|Selected, delta)\n"
4009 "ChangeSize(SelectedLines|SelectedPins|SelectedVias, delta)\n"
4010 "ChangeSize(SelectedPads|SelectedTexts|SelectedNames, delta)\n"
4011 "ChangeSize(SelectedElements, delta)";
4013 static const char changesize_help
[] = "Changes the size of objects.";
4015 /* %start-doc actions ChangeSize
4017 For lines and arcs, this changes the width. For pins and vias, this
4018 changes the overall diameter of the copper annulus. For pads, this
4019 changes the width and, indirectly, the length. For texts and names,
4020 this changes the scaling factor. For elements, this changes the width
4021 of the silk layer lines and arcs for this element.
4026 ActionChangeSize (int argc
, char **argv
, Coord x
, Coord y
)
4028 char *function
= ARG (0);
4029 char *delta
= ARG (1);
4030 char *units
= ARG (2);
4031 bool absolute
; /* indicates if absolute size is given */
4034 if (function
&& delta
)
4036 value
= GetValue (delta
, units
, &absolute
);
4038 value
= delta
[0] == '-' ? -Settings
.increments
->size
4039 : Settings
.increments
->size
;
4040 switch (GetFunctionID (function
))
4045 void *ptr1
, *ptr2
, *ptr3
;
4048 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
4049 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4050 if (TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
4051 Message (_("Sorry, the object is locked\n"));
4052 if (ChangeObjectSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4053 SetChangedFlag (true);
4057 case F_SelectedVias
:
4058 if (ChangeSelectedSize (VIA_TYPE
, value
, absolute
))
4059 SetChangedFlag (true);
4062 case F_SelectedPins
:
4063 if (ChangeSelectedSize (PIN_TYPE
, value
, absolute
))
4064 SetChangedFlag (true);
4067 case F_SelectedPads
:
4068 if (ChangeSelectedSize (PAD_TYPE
, value
, absolute
))
4069 SetChangedFlag (true);
4072 case F_SelectedArcs
:
4073 if (ChangeSelectedSize (ARC_TYPE
, value
, absolute
))
4074 SetChangedFlag (true);
4077 case F_SelectedLines
:
4078 if (ChangeSelectedSize (LINE_TYPE
, value
, absolute
))
4079 SetChangedFlag (true);
4082 case F_SelectedTexts
:
4083 if (ChangeSelectedSize (TEXT_TYPE
, value
, absolute
))
4084 SetChangedFlag (true);
4087 case F_SelectedNames
:
4088 if (ChangeSelectedSize (ELEMENTNAME_TYPE
, value
, absolute
))
4089 SetChangedFlag (true);
4092 case F_SelectedElements
:
4093 if (ChangeSelectedSize (ELEMENT_TYPE
, value
, absolute
))
4094 SetChangedFlag (true);
4098 case F_SelectedObjects
:
4099 if (ChangeSelectedSize (CHANGESIZE_TYPES
, value
, absolute
))
4100 SetChangedFlag (true);
4107 /* --------------------------------------------------------------------------- */
4109 static const char changedrillsize_syntax
[] =
4110 "ChangeDrillSize(Object, delta)\n"
4111 "ChangeDrillSize(SelectedPins|SelectedVias|Selected|SelectedObjects, delta)";
4113 static const char changedrillsize_help
[] =
4114 "Changes the drilling hole size of objects.";
4116 /* %start-doc actions ChangeDrillSize
4121 ActionChange2ndSize (int argc
, char **argv
, Coord x
, Coord y
)
4123 char *function
= ARG (0);
4124 char *delta
= ARG (1);
4125 char *units
= ARG (2);
4129 if (function
&& delta
)
4131 value
= GetValue (delta
, units
, &absolute
);
4132 switch (GetFunctionID (function
))
4137 void *ptr1
, *ptr2
, *ptr3
;
4139 gui
->get_coords (_("Select an Object"), &x
, &y
);
4141 SearchScreen (x
, y
, CHANGE2NDSIZE_TYPES
,
4142 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4143 if (ChangeObject2ndSize
4144 (type
, ptr1
, ptr2
, ptr3
, value
, absolute
, true))
4145 SetChangedFlag (true);
4149 case F_SelectedVias
:
4150 if (ChangeSelected2ndSize (VIA_TYPE
, value
, absolute
))
4151 SetChangedFlag (true);
4154 case F_SelectedPins
:
4155 if (ChangeSelected2ndSize (PIN_TYPE
, value
, absolute
))
4156 SetChangedFlag (true);
4159 case F_SelectedObjects
:
4160 if (ChangeSelected2ndSize (PIN_TYPES
, value
, absolute
))
4161 SetChangedFlag (true);
4168 /* --------------------------------------------------------------------------- */
4170 static const char changeclearsize_syntax
[] =
4171 "ChangeClearSize(Object, delta)\n"
4172 "ChangeClearSize(SelectedPins|SelectedPads|SelectedVias, delta)\n"
4173 "ChangeClearSize(SelectedLines|SelectedArcs, delta\n"
4174 "ChangeClearSize(Selected|SelectedObjects, delta)";
4176 static const char changeclearsize_help
[] =
4177 "Changes the clearance size of objects.";
4179 /* %start-doc actions ChangeClearSize
4181 If the solder mask is currently showing, this action changes the
4182 solder mask clearance. If the mask is not showing, this action
4183 changes the polygon clearance.
4188 ActionChangeClearSize (int argc
, char **argv
, Coord x
, Coord y
)
4190 char *function
= ARG (0);
4191 char *delta
= ARG (1);
4192 char *units
= ARG (2);
4196 if (function
&& delta
)
4198 value
= 2 * GetValue (delta
, units
, &absolute
);
4200 value
= delta
[0] == '-' ? -Settings
.increments
->clear
4201 : Settings
.increments
->clear
;
4202 switch (GetFunctionID (function
))
4207 void *ptr1
, *ptr2
, *ptr3
;
4209 gui
->get_coords (_("Select an Object"), &x
, &y
);
4212 CHANGECLEARSIZE_TYPES
, &ptr1
, &ptr2
,
4214 if (ChangeObjectClearSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4215 SetChangedFlag (true);
4218 case F_SelectedVias
:
4219 if (ChangeSelectedClearSize (VIA_TYPE
, value
, absolute
))
4220 SetChangedFlag (true);
4222 case F_SelectedPads
:
4223 if (ChangeSelectedClearSize (PAD_TYPE
, value
, absolute
))
4224 SetChangedFlag (true);
4226 case F_SelectedPins
:
4227 if (ChangeSelectedClearSize (PIN_TYPE
, value
, absolute
))
4228 SetChangedFlag (true);
4230 case F_SelectedLines
:
4231 if (ChangeSelectedClearSize (LINE_TYPE
, value
, absolute
))
4232 SetChangedFlag (true);
4234 case F_SelectedArcs
:
4235 if (ChangeSelectedClearSize (ARC_TYPE
, value
, absolute
))
4236 SetChangedFlag (true);
4239 case F_SelectedObjects
:
4240 if (ChangeSelectedClearSize (CHANGECLEARSIZE_TYPES
, value
, absolute
))
4241 SetChangedFlag (true);
4248 /* --------------------------------------------------------------------------- */
4250 static const char minmaskgap_syntax
[] =
4251 "MinMaskGap(delta)\n"
4252 "MinMaskGap(Selected, delta)";
4254 static const char minmaskgap_help
[] =
4255 "Ensures the mask is a minimum distance from pins and pads.";
4257 /* %start-doc actions MinMaskGap
4259 Checks all specified pins and/or pads, and increases the mask if
4260 needed to ensure a minimum distance between the pin or pad edge and
4266 ActionMinMaskGap (int argc
, char **argv
, Coord x
, Coord y
)
4268 char *function
= ARG (0);
4269 char *delta
= ARG (1);
4270 char *units
= ARG (2);
4277 if (strcasecmp (function
, "Selected") == 0)
4278 flags
= SELECTEDFLAG
;
4285 value
= 2 * GetValue (delta
, units
, &absolute
);
4287 SaveUndoSerialNumber ();
4288 ELEMENT_LOOP (PCB
->Data
);
4292 if (!TEST_FLAGS (flags
, pin
))
4294 if (pin
->Mask
< pin
->Thickness
+ value
)
4296 ChangeObjectMaskSize (PIN_TYPE
, element
, pin
, 0,
4297 pin
->Thickness
+ value
, 1);
4298 RestoreUndoSerialNumber ();
4304 if (!TEST_FLAGS (flags
, pad
))
4306 if (pad
->Mask
< pad
->Thickness
+ value
)
4308 ChangeObjectMaskSize (PAD_TYPE
, element
, pad
, 0,
4309 pad
->Thickness
+ value
, 1);
4310 RestoreUndoSerialNumber ();
4316 VIA_LOOP (PCB
->Data
);
4318 if (!TEST_FLAGS (flags
, via
))
4320 if (via
->Mask
&& via
->Mask
< via
->Thickness
+ value
)
4322 ChangeObjectMaskSize (VIA_TYPE
, via
, 0, 0, via
->Thickness
+ value
, 1);
4323 RestoreUndoSerialNumber ();
4327 RestoreUndoSerialNumber ();
4328 IncrementUndoSerialNumber ();
4332 /* --------------------------------------------------------------------------- */
4334 static const char mincleargap_syntax
[] =
4335 "MinClearGap(delta)\n"
4336 "MinClearGap(Selected, delta)";
4338 static const char mincleargap_help
[] =
4339 "Ensures that polygons are a minimum distance from objects.";
4341 /* %start-doc actions MinClearGap
4343 Checks all specified objects, and increases the polygon clearance if
4344 needed to ensure a minimum distance between their edges and the
4350 ActionMinClearGap (int argc
, char **argv
, Coord x
, Coord y
)
4352 char *function
= ARG (0);
4353 char *delta
= ARG (1);
4354 char *units
= ARG (2);
4361 if (strcasecmp (function
, "Selected") == 0)
4362 flags
= SELECTEDFLAG
;
4369 value
= 2 * GetValue (delta
, units
, &absolute
);
4371 SaveUndoSerialNumber ();
4372 ELEMENT_LOOP (PCB
->Data
);
4376 if (!TEST_FLAGS (flags
, pin
))
4378 if (pin
->Clearance
< value
)
4380 ChangeObjectClearSize (PIN_TYPE
, element
, pin
, 0,
4382 RestoreUndoSerialNumber ();
4388 if (!TEST_FLAGS (flags
, pad
))
4390 if (pad
->Clearance
< value
)
4392 ChangeObjectClearSize (PAD_TYPE
, element
, pad
, 0,
4394 RestoreUndoSerialNumber ();
4400 VIA_LOOP (PCB
->Data
);
4402 if (!TEST_FLAGS (flags
, via
))
4404 if (via
->Clearance
< value
)
4406 ChangeObjectClearSize (VIA_TYPE
, via
, 0, 0, value
, 1);
4407 RestoreUndoSerialNumber ();
4411 ALLLINE_LOOP (PCB
->Data
);
4413 if (!TEST_FLAGS (flags
, line
))
4415 if (line
->Clearance
< value
)
4417 ChangeObjectClearSize (LINE_TYPE
, layer
, line
, 0, value
, 1);
4418 RestoreUndoSerialNumber ();
4422 ALLARC_LOOP (PCB
->Data
);
4424 if (!TEST_FLAGS (flags
, arc
))
4426 if (arc
->Clearance
< value
)
4428 ChangeObjectClearSize (ARC_TYPE
, layer
, arc
, 0, value
, 1);
4429 RestoreUndoSerialNumber ();
4433 RestoreUndoSerialNumber ();
4434 IncrementUndoSerialNumber ();
4438 /* --------------------------------------------------------------------------- */
4440 static const char changepinname_syntax
[] =
4441 "ChangePinName(ElementName,PinNumber,PinName)";
4443 static const char changepinname_help
[] =
4444 "Sets the name of a specific pin on a specific element.";
4446 /* %start-doc actions ChangePinName
4448 This can be especially useful for annotating pin names from a
4449 schematic to the layout without requiring knowledge of the pcb file
4453 ChangePinName(U3, 7, VCC)
4459 ActionChangePinName (int argc
, char **argv
, Coord x
, Coord y
)
4462 char *refdes
, *pinnum
, *pinname
;
4466 AFAIL (changepinname
);
4473 ELEMENT_LOOP (PCB
->Data
);
4475 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
4479 if (NSTRCMP (pinnum
, pin
->Number
) == 0)
4481 AddObjectToChangeNameUndoList (PIN_TYPE
, NULL
, NULL
,
4484 * Note: we can't free() pin->Name first because
4485 * it is used in the undo list
4487 pin
->Name
= strdup (pinname
);
4488 SetChangedFlag (true);
4496 if (NSTRCMP (pinnum
, pad
->Number
) == 0)
4498 AddObjectToChangeNameUndoList (PAD_TYPE
, NULL
, NULL
,
4501 * Note: we can't free() pad->Name first because
4502 * it is used in the undo list
4504 pad
->Name
= strdup (pinname
);
4505 SetChangedFlag (true);
4514 * done with our action so increment the undo # if we actually
4520 defer_needs_update
= 1;
4523 IncrementUndoSerialNumber ();
4524 gui
->invalidate_all ();
4531 /* --------------------------------------------------------------------------- */
4533 static const char changename_syntax
[] =
4534 "ChangeName(Object)\n"
4535 "ChangeName(Layout|Layer)";
4537 static const char changename_help
[] = "Sets the name of objects.";
4539 /* %start-doc actions ChangeName
4544 Changes the name of the element under the cursor.
4547 Changes the name of the layout. This is printed on the fab drawings.
4550 Changes the name of the currently active layer.
4557 ActionChangeName (int argc
, char **argv
, Coord x
, Coord y
)
4559 char *function
= ARG (0);
4564 switch (GetFunctionID (function
))
4566 /* change the name of an object */
4570 void *ptr1
, *ptr2
, *ptr3
;
4572 gui
->get_coords (_("Select an Object"), &x
, &y
);
4574 SearchScreen (x
, y
, CHANGENAME_TYPES
,
4575 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4577 SaveUndoSerialNumber ();
4578 if (QueryInputAndChangeObjectName (type
, ptr1
, ptr2
, ptr3
))
4580 SetChangedFlag (true);
4581 if (type
== ELEMENT_TYPE
)
4583 RubberbandType
*ptr
;
4586 RestoreUndoSerialNumber ();
4587 Crosshair
.AttachedObject
.RubberbandN
= 0;
4588 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
4589 ptr
= Crosshair
.AttachedObject
.Rubberband
;
4590 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
;
4594 EraseRat ((RatType
*) ptr
->Line
);
4595 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
4596 ptr
->Line
, ptr
->Line
,
4599 IncrementUndoSerialNumber ();
4607 /* change the layout's name */
4610 gui
->prompt_for (_("Enter the layout name:"), EMPTY (PCB
->Name
));
4611 /* NB: ChangeLayoutName takes ownership of the passed memory */
4612 if (name
&& ChangeLayoutName (name
))
4613 SetChangedFlag (true);
4616 /* change the name of the active layer */
4618 name
= gui
->prompt_for (_("Enter the layer name:"),
4619 EMPTY (CURRENT
->Name
));
4620 /* NB: ChangeLayerName takes ownership of the passed memory */
4621 if (name
&& ChangeLayerName (CURRENT
, name
))
4622 SetChangedFlag (true);
4630 /* --------------------------------------------------------------------------- */
4632 static const char morphpolygon_syntax
[] = "MorphPolygon(Object|Selected)";
4634 static const char morphpolygon_help
[] =
4635 "Converts dead polygon islands into separate polygons.";
4637 /* %start-doc actions MorphPolygon
4639 If a polygon is divided into unconnected "islands", you can use
4640 this command to convert the otherwise disappeared islands into
4641 separate polygons. Be sure the cursor is over a portion of the
4642 polygon that remains visible. Very small islands that may flake
4643 off are automatically deleted.
4648 ActionMorphPolygon (int argc
, char **argv
, Coord x
, Coord y
)
4650 char *function
= ARG (0);
4653 switch (GetFunctionID (function
))
4658 void *ptr1
, *ptr2
, *ptr3
;
4660 gui
->get_coords (_("Select an Object"), &x
, &y
);
4661 if ((type
= SearchScreen (x
, y
, POLYGON_TYPE
,
4662 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4664 MorphPolygon ((LayerType
*) ptr1
, (PolygonType
*) ptr3
);
4666 IncrementUndoSerialNumber ();
4671 case F_SelectedObjects
:
4672 ALLPOLYGON_LOOP (PCB
->Data
);
4674 if (TEST_FLAG (SELECTEDFLAG
, polygon
))
4675 MorphPolygon (layer
, polygon
);
4679 IncrementUndoSerialNumber ();
4686 /* --------------------------------------------------------------------------- */
4688 static const char togglehidename_syntax
[] =
4689 "ToggleHideName(Object|SelectedElements)";
4691 static const char togglehidename_help
[] =
4692 "Toggles the visibility of element names.";
4694 /* %start-doc actions ToggleHideName
4696 If names are hidden you won't see them on the screen and they will not
4697 appear on the silk layer when you print the layout.
4702 ActionToggleHideName (int argc
, char **argv
, Coord x
, Coord y
)
4704 char *function
= ARG (0);
4705 if (function
&& PCB
->ElementOn
)
4707 switch (GetFunctionID (function
))
4712 void *ptr1
, *ptr2
, *ptr3
;
4714 gui
->get_coords (_("Select an Object"), &x
, &y
);
4715 if ((type
= SearchScreen (x
, y
, ELEMENT_TYPE
,
4716 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4718 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr3
);
4719 EraseElementName ((ElementType
*) ptr2
);
4720 TOGGLE_FLAG (HIDENAMEFLAG
, (ElementType
*) ptr2
);
4721 DrawElementName ((ElementType
*) ptr2
);
4723 IncrementUndoSerialNumber ();
4727 case F_SelectedElements
:
4730 bool changed
= false;
4731 ELEMENT_LOOP (PCB
->Data
);
4733 if ((TEST_FLAG (SELECTEDFLAG
, element
) ||
4734 TEST_FLAG (SELECTEDFLAG
,
4735 &NAMEONPCB_TEXT (element
)))
4736 && (FRONT (element
) || PCB
->InvisibleObjectsOn
))
4738 AddObjectToFlagUndoList (ELEMENT_TYPE
, element
,
4740 EraseElementName (element
);
4741 TOGGLE_FLAG (HIDENAMEFLAG
, element
);
4742 DrawElementName (element
);
4750 IncrementUndoSerialNumber ();
4758 /* --------------------------------------------------------------------------- */
4760 static const char changejoin_syntax
[] =
4761 "ChangeJoin(ToggleObject|SelectedLines|SelectedArcs|Selected)";
4763 static const char changejoin_help
[] =
4764 "Changes the join (clearance through polygons) of objects.";
4766 /* %start-doc actions ChangeJoin
4768 The join flag determines whether a line or arc, drawn to intersect a
4769 polygon, electrically connects to the polygon or not. When joined,
4770 the line/arc is simply drawn over the polygon, making an electrical
4771 connection. When not joined, a gap is drawn between the line and the
4772 polygon, insulating them from each other.
4777 ActionChangeJoin (int argc
, char **argv
, Coord x
, Coord y
)
4779 char *function
= ARG (0);
4782 switch (GetFunctionID (function
))
4784 case F_ToggleObject
:
4788 void *ptr1
, *ptr2
, *ptr3
;
4790 gui
->get_coords (_("Select an Object"), &x
, &y
);
4792 SearchScreen (x
, y
, CHANGEJOIN_TYPES
,
4793 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4794 if (ChangeObjectJoin (type
, ptr1
, ptr2
, ptr3
))
4795 SetChangedFlag (true);
4799 case F_SelectedLines
:
4800 if (ChangeSelectedJoin (LINE_TYPE
))
4801 SetChangedFlag (true);
4804 case F_SelectedArcs
:
4805 if (ChangeSelectedJoin (ARC_TYPE
))
4806 SetChangedFlag (true);
4810 case F_SelectedObjects
:
4811 if (ChangeSelectedJoin (CHANGEJOIN_TYPES
))
4812 SetChangedFlag (true);
4819 /* --------------------------------------------------------------------------- */
4821 static const char changesquare_syntax
[] =
4822 "ChangeSquare(ToggleObject)\n"
4823 "ChangeSquare(SelectedElements|SelectedPins)\n"
4824 "ChangeSquare(Selected|SelectedObjects)";
4826 static const char changesquare_help
[] =
4827 "Changes the square flag of pins and pads.";
4829 /* %start-doc actions ChangeSquare
4831 Note that @code{Pins} means both pins and pads.
4838 ActionChangeSquare (int argc
, char **argv
, Coord x
, Coord y
)
4840 char *function
= ARG (0);
4843 switch (GetFunctionID (function
))
4845 case F_ToggleObject
:
4849 void *ptr1
, *ptr2
, *ptr3
;
4851 gui
->get_coords (_("Select an Object"), &x
, &y
);
4853 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4854 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4855 if (ChangeObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4856 SetChangedFlag (true);
4860 case F_SelectedElements
:
4861 if (ChangeSelectedSquare (ELEMENT_TYPE
))
4862 SetChangedFlag (true);
4865 case F_SelectedPins
:
4866 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4867 SetChangedFlag (true);
4871 case F_SelectedObjects
:
4872 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4873 SetChangedFlag (true);
4880 /* --------------------------------------------------------------------------- */
4882 static const char setsquare_syntax
[] =
4883 "SetSquare(ToggleObject|SelectedElements|SelectedPins)";
4885 static const char setsquare_help
[] = "sets the square-flag of objects.";
4887 /* %start-doc actions SetSquare
4889 Note that @code{Pins} means pins and pads.
4896 ActionSetSquare (int argc
, char **argv
, Coord x
, Coord y
)
4898 char *function
= ARG (0);
4899 if (function
&& *function
)
4901 switch (GetFunctionID (function
))
4903 case F_ToggleObject
:
4907 void *ptr1
, *ptr2
, *ptr3
;
4909 gui
->get_coords (_("Select an Object"), &x
, &y
);
4911 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4912 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4913 if (SetObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4914 SetChangedFlag (true);
4918 case F_SelectedElements
:
4919 if (SetSelectedSquare (ELEMENT_TYPE
))
4920 SetChangedFlag (true);
4923 case F_SelectedPins
:
4924 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4925 SetChangedFlag (true);
4929 case F_SelectedObjects
:
4930 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4931 SetChangedFlag (true);
4938 /* --------------------------------------------------------------------------- */
4940 static const char clearsquare_syntax
[] =
4941 "ClearSquare(ToggleObject|SelectedElements|SelectedPins)";
4943 static const char clearsquare_help
[] =
4944 "Clears the square-flag of pins and pads.";
4946 /* %start-doc actions ClearSquare
4948 Note that @code{Pins} means pins and pads.
4955 ActionClearSquare (int argc
, char **argv
, Coord x
, Coord y
)
4957 char *function
= ARG (0);
4958 if (function
&& *function
)
4960 switch (GetFunctionID (function
))
4962 case F_ToggleObject
:
4966 void *ptr1
, *ptr2
, *ptr3
;
4968 gui
->get_coords (_("Select an Object"), &x
, &y
);
4970 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4971 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4972 if (ClrObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4973 SetChangedFlag (true);
4977 case F_SelectedElements
:
4978 if (ClrSelectedSquare (ELEMENT_TYPE
))
4979 SetChangedFlag (true);
4982 case F_SelectedPins
:
4983 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4984 SetChangedFlag (true);
4988 case F_SelectedObjects
:
4989 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4990 SetChangedFlag (true);
4997 /* --------------------------------------------------------------------------- */
4999 static const char changeoctagon_syntax
[] =
5000 "ChangeOctagon(Object|ToggleObject|SelectedObjects|Selected)\n"
5001 "ChangeOctagon(SelectedElements|SelectedPins|SelectedVias)";
5003 static const char changeoctagon_help
[] =
5004 "Changes the octagon-flag of pins and vias.";
5006 /* %start-doc actions ChangeOctagon
5013 ActionChangeOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5015 char *function
= ARG (0);
5018 switch (GetFunctionID (function
))
5020 case F_ToggleObject
:
5024 void *ptr1
, *ptr2
, *ptr3
;
5026 gui
->get_coords (_("Select an Object"), &x
, &y
);
5028 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5029 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5030 if (ChangeObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5031 SetChangedFlag (true);
5035 case F_SelectedElements
:
5036 if (ChangeSelectedOctagon (ELEMENT_TYPE
))
5037 SetChangedFlag (true);
5040 case F_SelectedPins
:
5041 if (ChangeSelectedOctagon (PIN_TYPE
))
5042 SetChangedFlag (true);
5045 case F_SelectedVias
:
5046 if (ChangeSelectedOctagon (VIA_TYPE
))
5047 SetChangedFlag (true);
5051 case F_SelectedObjects
:
5052 if (ChangeSelectedOctagon (PIN_TYPES
))
5053 SetChangedFlag (true);
5060 /* --------------------------------------------------------------------------- */
5062 static const char setoctagon_syntax
[] =
5063 "SetOctagon(Object|ToggleObject|SelectedElements|Selected)";
5065 static const char setoctagon_help
[] = "Sets the octagon-flag of objects.";
5067 /* %start-doc actions SetOctagon
5074 ActionSetOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5076 char *function
= ARG (0);
5079 switch (GetFunctionID (function
))
5081 case F_ToggleObject
:
5085 void *ptr1
, *ptr2
, *ptr3
;
5087 gui
->get_coords (_("Select an Object"), &x
, &y
);
5089 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5090 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5091 if (SetObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5092 SetChangedFlag (true);
5096 case F_SelectedElements
:
5097 if (SetSelectedOctagon (ELEMENT_TYPE
))
5098 SetChangedFlag (true);
5101 case F_SelectedPins
:
5102 if (SetSelectedOctagon (PIN_TYPE
))
5103 SetChangedFlag (true);
5106 case F_SelectedVias
:
5107 if (SetSelectedOctagon (VIA_TYPE
))
5108 SetChangedFlag (true);
5112 case F_SelectedObjects
:
5113 if (SetSelectedOctagon (PIN_TYPES
))
5114 SetChangedFlag (true);
5121 /* --------------------------------------------------------------------------- */
5123 static const char clearoctagon_syntax
[] =
5124 "ClearOctagon(ToggleObject|Object|SelectedObjects|Selected)\n"
5125 "ClearOctagon(SelectedElements|SelectedPins|SelectedVias)";
5127 static const char clearoctagon_help
[] =
5128 "Clears the octagon-flag of pins and vias.";
5130 /* %start-doc actions ClearOctagon
5137 ActionClearOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5139 char *function
= ARG (0);
5142 switch (GetFunctionID (function
))
5144 case F_ToggleObject
:
5148 void *ptr1
, *ptr2
, *ptr3
;
5150 gui
->get_coords (_("Select an Object"), &x
, &y
);
5152 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGEOCTAGON_TYPES
,
5153 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5154 if (ClrObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5155 SetChangedFlag (true);
5159 case F_SelectedElements
:
5160 if (ClrSelectedOctagon (ELEMENT_TYPE
))
5161 SetChangedFlag (true);
5164 case F_SelectedPins
:
5165 if (ClrSelectedOctagon (PIN_TYPE
))
5166 SetChangedFlag (true);
5169 case F_SelectedVias
:
5170 if (ClrSelectedOctagon (VIA_TYPE
))
5171 SetChangedFlag (true);
5175 case F_SelectedObjects
:
5176 if (ClrSelectedOctagon (PIN_TYPES
))
5177 SetChangedFlag (true);
5184 /* --------------------------------------------------------------------------- */
5186 static const char changehold_syntax
[] =
5187 "ChangeHole(ToggleObject|Object|SelectedVias|Selected)";
5189 static const char changehold_help
[] = "Changes the hole flag of objects.";
5191 /* %start-doc actions ChangeHole
5193 The "hole flag" of a via determines whether the via is a
5194 plated-through hole (not set), or an unplated hole (set).
5199 ActionChangeHole (int argc
, char **argv
, Coord x
, Coord y
)
5201 char *function
= ARG (0);
5204 switch (GetFunctionID (function
))
5206 case F_ToggleObject
:
5210 void *ptr1
, *ptr2
, *ptr3
;
5212 gui
->get_coords (_("Select an Object"), &x
, &y
);
5213 if ((type
= SearchScreen (x
, y
, VIA_TYPE
,
5214 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5215 && ChangeHole ((PinType
*) ptr3
))
5216 IncrementUndoSerialNumber ();
5220 case F_SelectedVias
:
5222 if (ChangeSelectedHole ())
5223 SetChangedFlag (true);
5230 /* --------------------------------------------------------------------------- */
5232 static const char changepaste_syntax
[] =
5233 "ChangePaste(ToggleObject|Object|SelectedPads|Selected)";
5235 static const char changepaste_help
[] = "Changes the no paste flag of objects.";
5237 /* %start-doc actions ChangePaste
5239 The "no paste flag" of a pad determines whether the solderpaste
5240 stencil will have an opening for the pad (no set) or if there wil be
5241 no solderpaste on the pad (set). This is used for things such as
5247 ActionChangePaste (int argc
, char **argv
, Coord x
, Coord y
)
5249 char *function
= ARG (0);
5252 switch (GetFunctionID (function
))
5254 case F_ToggleObject
:
5258 void *ptr1
, *ptr2
, *ptr3
;
5260 gui
->get_coords (_("Select an Object"), &x
, &y
);
5261 if ((type
= SearchScreen (x
, y
, PAD_TYPE
,
5262 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5263 && ChangePaste ((PadType
*) ptr3
))
5264 IncrementUndoSerialNumber ();
5268 case F_SelectedPads
:
5270 if (ChangeSelectedPaste ())
5271 SetChangedFlag (true);
5278 /* --------------------------------------------------------------------------- */
5280 static const char select_syntax
[] =
5281 "Select(Object|ToggleObject)\n"
5282 "Select(All|Block|Connection)\n"
5283 "Select(ElementByName|ObjectByName|PadByName|PinByName)\n"
5284 "Select(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5285 "Select(TextByName|ViaByName|NetByName)\n"
5286 "Select(TextByName|ViaByName|NetByName, Name)\n"
5289 static const char select_help
[] = "Toggles or sets the selection.";
5291 /* %start-doc actions Select
5303 These all rely on having a regular expression parser built into
5304 @code{pcb}. If the name is not specified then the user is prompted
5305 for a pattern, and all objects that match the pattern and are of the
5306 type specified are selected.
5310 Selects the object under the cursor.
5313 Selects all objects in a rectangle indicated by the cursor.
5316 Selects all objects on the board.
5319 Selects all connections with the ``found'' flag set.
5322 Converts the selected objects to an element. This uses the highest
5323 numbered paste buffer.
5330 ActionSelect (int argc
, char **argv
, Coord x
, Coord y
)
5332 char *function
= ARG (0);
5335 switch (GetFunctionID (function
))
5337 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5339 /* select objects by their names */
5340 case F_ElementByName
:
5341 type
= ELEMENT_TYPE
;
5343 case F_ObjectByName
:
5364 char *pattern
= ARG (1);
5368 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5370 if (SelectObjectByName (type
, pattern
, true))
5371 SetChangedFlag (true);
5372 if (ARG (1) == NULL
)
5377 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5379 /* select a single object */
5380 case F_ToggleObject
:
5382 if (SelectObject ())
5383 SetChangedFlag (true);
5386 /* all objects in block */
5391 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5392 Crosshair
.AttachedBox
.Point2
.X
);
5393 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5394 Crosshair
.AttachedBox
.Point2
.Y
);
5395 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5396 Crosshair
.AttachedBox
.Point2
.X
);
5397 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5398 Crosshair
.AttachedBox
.Point2
.Y
);
5399 notify_crosshair_change (false);
5401 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5402 SelectBlock (&box
, true))
5404 SetChangedFlag (true);
5405 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5407 notify_crosshair_change (true);
5411 /* select all visible objects */
5416 box
.X1
= -MAX_COORD
;
5417 box
.Y1
= -MAX_COORD
;
5420 if (SelectBlock (&box
, true))
5421 SetChangedFlag (true);
5425 /* all found connections */
5427 if (SelectConnection (true))
5430 IncrementUndoSerialNumber ();
5431 SetChangedFlag (true);
5438 Note
.Buffer
= Settings
.BufferNumber
;
5439 SetBufferNumber (MAX_BUFFER
- 1);
5440 ClearBuffer (PASTEBUFFER
);
5441 gui
->get_coords (_("Select the Element's Mark Location"), &x
, &y
);
5442 x
= GridFit (x
, PCB
->Grid
, PCB
->GridOffsetX
);
5443 y
= GridFit (y
, PCB
->Grid
, PCB
->GridOffsetY
);
5444 AddSelectedToBuffer (PASTEBUFFER
, x
, y
, true);
5445 SaveUndoSerialNumber ();
5447 ConvertBufferToElement (PASTEBUFFER
);
5448 RestoreUndoSerialNumber ();
5449 CopyPastebufferToLayout (x
, y
);
5450 SetBufferNumber (Note
.Buffer
);
5462 /* FLAG(have_regex,FlagHaveRegex,0) */
5464 FlagHaveRegex (int parm
)
5466 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5473 /* --------------------------------------------------------------------------- */
5475 static const char unselect_syntax
[] =
5476 "Unselect(All|Block|Connection)\n"
5477 "Unselect(ElementByName|ObjectByName|PadByName|PinByName)\n"
5478 "Unselect(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5479 "Unselect(TextByName|ViaByName)\n"
5480 "Unselect(TextByName|ViaByName, Name)\n";
5482 static const char unselect_help
[] =
5483 "Unselects the object at the pointer location or the specified objects.";
5485 /* %start-doc actions Unselect
5490 Unselect all objects.
5493 Unselect all objects in a rectangle given by the cursor.
5496 Unselect all connections with the ``found'' flag set.
5505 These all rely on having a regular expression parser built into
5506 @code{pcb}. If the name is not specified then the user is prompted
5507 for a pattern, and all objects that match the pattern and are of the
5508 type specified are unselected.
5516 ActionUnselect (int argc
, char **argv
, Coord x
, Coord y
)
5518 char *function
= ARG (0);
5521 switch (GetFunctionID (function
))
5523 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5525 /* select objects by their names */
5526 case F_ElementByName
:
5527 type
= ELEMENT_TYPE
;
5529 case F_ObjectByName
:
5550 char *pattern
= ARG (1);
5554 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5556 if (SelectObjectByName (type
, pattern
, false))
5557 SetChangedFlag (true);
5558 if (ARG (1) == NULL
)
5563 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5565 /* all objects in block */
5570 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5571 Crosshair
.AttachedBox
.Point2
.X
);
5572 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5573 Crosshair
.AttachedBox
.Point2
.Y
);
5574 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5575 Crosshair
.AttachedBox
.Point2
.X
);
5576 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5577 Crosshair
.AttachedBox
.Point2
.Y
);
5578 notify_crosshair_change (false);
5580 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5581 SelectBlock (&box
, false))
5583 SetChangedFlag (true);
5584 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5586 notify_crosshair_change (true);
5590 /* unselect all visible objects */
5595 box
.X1
= -MAX_COORD
;
5596 box
.Y1
= -MAX_COORD
;
5599 if (SelectBlock (&box
, false))
5600 SetChangedFlag (true);
5604 /* all found connections */
5606 if (SelectConnection (false))
5609 IncrementUndoSerialNumber ();
5610 SetChangedFlag (true);
5623 /* --------------------------------------------------------------------------- */
5625 static const char saveto_syntax
[] =
5626 "SaveTo(Layout|LayoutAs,filename)\n"
5627 "SaveTo(AllConnections|AllUnusedPins|ElementConnections,filename)\n"
5628 "SaveTo(PasteBuffer,filename)";
5630 static const char saveto_help
[] = "Saves data to a file.";
5632 /* %start-doc actions SaveTo
5637 Saves the current layout.
5640 Saves the current layout, and remembers the filename used.
5642 @item AllConnections
5643 Save all connections to a file.
5646 List all unused pins to a file.
5648 @item ElementConnections
5649 Save connections to the element at the cursor to a file.
5652 Save the content of the active Buffer to a file. This is the graphical way to create a footprint.
5659 ActionSaveTo (int argc
, char **argv
, Coord x
, Coord y
)
5667 if (strcasecmp (function
, "Layout") == 0)
5669 if (SavePCB (PCB
->Filename
) == 0)
5670 SetChangedFlag (false);
5677 if (strcasecmp (function
, "LayoutAs") == 0)
5679 if (SavePCB (name
) == 0)
5681 SetChangedFlag (false);
5682 free (PCB
->Filename
);
5683 PCB
->Filename
= strdup (name
);
5684 if (gui
->notify_filename_changed
!= NULL
)
5685 gui
->notify_filename_changed ();
5690 if (strcasecmp (function
, "AllConnections") == 0)
5694 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5696 LookupConnectionsToAllElements (fp
);
5698 SetChangedFlag (true);
5703 if (strcasecmp (function
, "AllUnusedPins") == 0)
5707 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5709 LookupUnusedPins (fp
);
5711 SetChangedFlag (true);
5716 if (strcasecmp (function
, "ElementConnections") == 0)
5718 ElementType
*element
;
5723 if ((SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
5724 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
5726 element
= (ElementType
*) ptrtmp
;
5728 CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5730 LookupElementConnections (element
, fp
);
5732 SetChangedFlag (true);
5738 if (strcasecmp (function
, "PasteBuffer") == 0)
5740 return SaveBufferElements (name
);
5746 /* --------------------------------------------------------------------------- */
5748 static const char savesettings_syntax
[] =
5750 "SaveSettings(local)";
5752 static const char savesettings_help
[] = "Saves settings.";
5754 /* %start-doc actions SaveSettings
5756 If you pass no arguments, the settings are stored in
5757 @code{$HOME/.pcb/settings}. If you pass the word @code{local} they're
5758 saved in @code{./pcb.settings}.
5763 ActionSaveSettings (int argc
, char **argv
, Coord x
, Coord y
)
5765 int locally
= argc
> 0 ? (strncasecmp (argv
[0], "local", 5) == 0) : 0;
5766 hid_save_settings (locally
);
5770 /* --------------------------------------------------------------------------- */
5772 static const char loadfrom_syntax
[] =
5773 "LoadFrom(Layout|LayoutToBuffer|ElementToBuffer|Netlist|Revert,filename)";
5775 static const char loadfrom_help
[] = "Load layout data from a file.";
5777 /* %start-doc actions LoadFrom
5779 This action assumes you know what the filename is. The various GUIs
5780 should have a similar @code{Load} action where the filename is
5781 optional, and will provide their own file selection mechanism to let
5782 you choose the file name.
5787 Loads an entire PCB layout, replacing the current one.
5789 @item LayoutToBuffer
5790 Loads an entire PCB layout to the paste buffer.
5792 @item ElementToBuffer
5793 Loads the given element file into the paste buffer. Element files
5794 contain only a single @code{Element} definition, such as the
5795 ``newlib'' library uses.
5798 Loads a new netlist, replacing any current netlist.
5801 Re-loads the current layout from its disk file, reverting any changes
5809 ActionLoadFrom (int argc
, char **argv
, Coord x
, Coord y
)
5820 if (strcasecmp (function
, "ElementToBuffer") == 0)
5822 notify_crosshair_change (false);
5823 if (LoadElementToBuffer (PASTEBUFFER
, name
, true))
5824 SetMode (PASTEBUFFER_MODE
);
5825 notify_crosshair_change (true);
5828 else if (strcasecmp (function
, "LayoutToBuffer") == 0)
5830 notify_crosshair_change (false);
5831 if (LoadLayoutToBuffer (PASTEBUFFER
, name
))
5832 SetMode (PASTEBUFFER_MODE
);
5833 notify_crosshair_change (true);
5836 else if (strcasecmp (function
, "Layout") == 0)
5838 if (!PCB
->Changed
||
5839 gui
->confirm_dialog (_("OK to override layout data?"), 0))
5843 else if (strcasecmp (function
, "Netlist") == 0)
5845 if (PCB
->Netlistname
)
5846 free (PCB
->Netlistname
);
5847 PCB
->Netlistname
= StripWhiteSpaceAndDup (name
);
5848 FreeLibraryMemory (&PCB
->NetlistLib
);
5849 ImportNetlist (PCB
->Netlistname
);
5852 else if (strcasecmp (function
, "Revert") == 0 && PCB
->Filename
5854 || gui
->confirm_dialog (_("OK to override changes?"), 0)))
5862 /* --------------------------------------------------------------------------- */
5864 static const char new_syntax
[] = "New([name])";
5866 static const char new_help
[] = "Starts a new layout.";
5868 /* %start-doc actions New
5870 If a name is not given, one is prompted for.
5875 ActionNew (int argc
, char **argv
, Coord x
, Coord y
)
5877 char *name
= ARG (0);
5879 if (!PCB
->Changed
|| gui
->confirm_dialog (_("OK to clear layout data?"), 0))
5882 name
= strdup (name
);
5884 name
= gui
->prompt_for (_("Enter the layout name:"), "");
5889 notify_crosshair_change (false);
5890 /* do emergency saving
5891 * clear the old struct and allocate memory for the new one
5893 if (PCB
->Changed
&& Settings
.SaveInTMP
)
5897 PCB
= CreateNewPCB (true);
5898 PCB
->Data
->LayerN
= DEF_LAYER
;
5899 CreateNewPCBPost (PCB
, 1);
5901 /* setup the new name and reset some values to default */
5905 ResetStackAndVisibility ();
5906 SetCrosshairRange (0, 0, PCB
->MaxWidth
, PCB
->MaxHeight
);
5907 CenterDisplay (PCB
->MaxWidth
/ 2, PCB
->MaxHeight
/ 2);
5910 hid_action ("PCBChanged");
5911 notify_crosshair_change (true);
5917 /* ---------------------------------------------------------------------------
5918 * no operation, just for testing purposes
5919 * syntax: Bell(volume)
5922 ActionBell (char *volume
)
5927 /* --------------------------------------------------------------------------- */
5929 static const char pastebuffer_syntax
[] =
5930 "PasteBuffer(AddSelected|Clear|1..MAX_BUFFER)\n"
5931 "PasteBuffer(Rotate, 1..3)\n"
5932 "PasteBuffer(Convert|Save|Restore|Mirror)\n"
5933 "PasteBuffer(ToLayout, X, Y, units)";
5935 static const char pastebuffer_help
[] =
5936 "Various operations on the paste buffer.";
5938 /* %start-doc actions PasteBuffer
5940 There are a number of paste buffers; the actual limit is a
5941 compile-time constant @code{MAX_BUFFER} in @file{globalconst.h}. It
5942 is currently @code{5}. One of these is the ``current'' paste buffer,
5943 often referred to as ``the'' paste buffer.
5948 Copies the selected objects to the current paste buffer.
5951 Remove all objects from the current paste buffer.
5954 Convert the current paste buffer to an element. Vias are converted to
5955 pins, lines are converted to pads.
5958 Convert any elements in the paste buffer back to vias and lines.
5961 Flip all objects in the paste buffer vertically (up/down flip). To mirror
5962 horizontally, combine this with rotations.
5965 Rotates the current buffer. The number to pass is 1..3, where 1 means
5966 90 degrees counter clockwise, 2 means 180 degrees, and 3 means 90
5967 degrees clockwise (270 CCW).
5970 Saves any elements in the current buffer to the indicated file.
5973 Pastes any elements in the current buffer to the indicated X, Y
5974 coordinates in the layout. The @code{X} and @code{Y} are treated like
5975 @code{delta} is for many other objects. For each, if it's prefixed by
5976 @code{+} or @code{-}, then that amount is relative to the last
5977 location. Otherwise, it's absolute. Units can be
5978 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
5979 units, currently 1/100 mil.
5983 Selects the given buffer to be the current paste buffer.
5990 ActionPasteBuffer (int argc
, char **argv
, Coord x
, Coord y
)
5992 char *function
= argc
? argv
[0] : (char *)"";
5993 char *sbufnum
= argc
> 1 ? argv
[1] : (char *)"";
5995 static char *default_file
= NULL
;
5998 notify_crosshair_change (false);
6001 switch (GetFunctionID (function
))
6003 /* clear contents of paste buffer */
6005 ClearBuffer (PASTEBUFFER
);
6008 /* copies objects to paste buffer */
6010 AddSelectedToBuffer (PASTEBUFFER
, 0, 0, false);
6013 /* converts buffer contents into an element */
6015 ConvertBufferToElement (PASTEBUFFER
);
6018 /* break up element for editing */
6020 SmashBufferElement (PASTEBUFFER
);
6025 MirrorBuffer (PASTEBUFFER
);
6031 RotateBuffer (PASTEBUFFER
, (BYTE
) atoi (sbufnum
));
6032 SetCrosshairRangeToBuffer ();
6037 if (PASTEBUFFER
->Data
->ElementN
== 0)
6039 Message (_("Buffer has no elements!\n"));
6045 name
= gui
->fileselect (_("Save Paste Buffer As ..."),
6046 _("Choose a file to save the contents of the\n"
6047 "paste buffer to.\n"),
6048 default_file
, ".fp", "footprint",
6053 free (default_file
);
6054 default_file
= NULL
;
6058 default_file
= strdup (name
);
6069 if ((exist
= fopen (name
, "r")))
6073 confirm_dialog (_("File exists! Ok to overwrite?"), 0))
6074 SaveBufferElements (name
);
6077 SaveBufferElements (name
);
6079 if (free_name
&& name
)
6086 static Coord oldx
= 0, oldy
= 0;
6094 else if (argc
== 3 || argc
== 4)
6096 x
= GetValue (ARG (1), ARG (3), &absolute
);
6099 y
= GetValue (ARG (2), ARG (3), &absolute
);
6105 notify_crosshair_change (true);
6106 AFAIL (pastebuffer
);
6111 if (CopyPastebufferToLayout (x
, y
))
6112 SetChangedFlag (true);
6119 int number
= atoi (function
);
6121 /* correct number */
6123 SetBufferNumber (number
- 1);
6128 notify_crosshair_change (true);
6132 /* --------------------------------------------------------------------------- */
6134 static const char undo_syntax
[] = "Undo()\n"
6137 static const char undo_help
[] = "Undo recent changes.";
6139 /* %start-doc actions Undo
6141 The unlimited undo feature of @code{Pcb} allows you to recover from
6142 most operations that materially affect you work. Calling
6143 @code{Undo()} without any parameter recovers from the last (non-undo)
6144 operation. @code{ClearList} is used to release the allocated
6145 memory. @code{ClearList} is called whenever a new layout is started or
6146 loaded. See also @code{Redo} and @code{Atomic}.
6148 Note that undo groups operations by serial number; changes with the
6149 same serial number will be undone (or redone) as a group. See
6155 ActionUndo (int argc
, char **argv
, Coord x
, Coord y
)
6157 char *function
= ARG (0);
6158 if (!function
|| !*function
)
6160 /* don't allow undo in the middle of an operation */
6161 if (Settings
.Mode
!= POLYGONHOLE_MODE
&&
6162 Crosshair
.AttachedObject
.State
!= STATE_FIRST
)
6164 if (Crosshair
.AttachedBox
.State
!= STATE_FIRST
6165 && Settings
.Mode
!= ARC_MODE
)
6167 /* undo the last operation */
6169 notify_crosshair_change (false);
6170 if ((Settings
.Mode
== POLYGON_MODE
||
6171 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6172 Crosshair
.AttachedPolygon
.PointN
)
6174 GoToPreviousPoint ();
6175 notify_crosshair_change (true);
6178 /* move anchor point if undoing during line creation */
6179 if (Settings
.Mode
== LINE_MODE
)
6181 if (Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6183 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6184 Undo (true); /* undo the connection find */
6185 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
6186 SetLocalRef (0, 0, false);
6187 notify_crosshair_change (true);
6190 if (Crosshair
.AttachedLine
.State
== STATE_THIRD
)
6193 void *ptr1
, *ptr3
, *ptrtmp
;
6195 /* this search is guaranteed to succeed */
6196 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6198 Crosshair
.AttachedLine
.Point1
.X
,
6199 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6200 ptr2
= (LineType
*) ptrtmp
;
6202 /* save both ends of line */
6203 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point1
.X
;
6204 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point1
.Y
;
6205 if ((type
= Undo (true)))
6206 SetChangedFlag (true);
6207 /* check that the undo was of the right type */
6208 if ((type
& UNDO_CREATE
) == 0)
6210 /* wrong undo type, restore anchor points */
6211 Crosshair
.AttachedLine
.Point2
.X
=
6212 Crosshair
.AttachedLine
.Point1
.X
;
6213 Crosshair
.AttachedLine
.Point2
.Y
=
6214 Crosshair
.AttachedLine
.Point1
.Y
;
6215 notify_crosshair_change (true);
6218 /* move to new anchor */
6219 Crosshair
.AttachedLine
.Point1
.X
=
6220 Crosshair
.AttachedLine
.Point2
.X
;
6221 Crosshair
.AttachedLine
.Point1
.Y
=
6222 Crosshair
.AttachedLine
.Point2
.Y
;
6223 /* check if an intermediate point was removed */
6224 if (type
& UNDO_REMOVE
)
6226 /* this search should find the restored line */
6227 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6230 Crosshair
.AttachedLine
.Point2
.X
,
6231 Crosshair
.AttachedLine
.Point2
.Y
, 0);
6232 ptr2
= (LineType
*) ptrtmp
;
6233 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6235 /* undo loses FOUNDFLAG */
6236 SET_FLAG(FOUNDFLAG
, ptr2
);
6237 DrawLine (CURRENT
, ptr2
);
6239 Crosshair
.AttachedLine
.Point1
.X
=
6240 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point2
.X
;
6241 Crosshair
.AttachedLine
.Point1
.Y
=
6242 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point2
.Y
;
6244 FitCrosshairIntoGrid (Crosshair
.X
, Crosshair
.Y
);
6245 AdjustAttachedObjects ();
6246 if (--addedLines
== 0)
6248 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
6249 lastLayer
= CURRENT
;
6253 /* this search is guaranteed to succeed too */
6254 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6257 Crosshair
.AttachedLine
.Point1
.X
,
6258 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6259 ptr2
= (LineType
*) ptrtmp
;
6260 lastLayer
= (LayerType
*) ptr1
;
6262 notify_crosshair_change (true);
6266 if (Settings
.Mode
== ARC_MODE
)
6268 if (Crosshair
.AttachedBox
.State
== STATE_SECOND
)
6270 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
6271 notify_crosshair_change (true);
6274 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
)
6276 void *ptr1
, *ptr2
, *ptr3
;
6278 /* guaranteed to succeed */
6279 SearchObjectByLocation (ARC_TYPE
, &ptr1
, &ptr2
, &ptr3
,
6280 Crosshair
.AttachedBox
.Point1
.X
,
6281 Crosshair
.AttachedBox
.Point1
.Y
, 0);
6282 bx
= GetArcEnds ((ArcType
*) ptr2
);
6283 Crosshair
.AttachedBox
.Point1
.X
=
6284 Crosshair
.AttachedBox
.Point2
.X
= bx
->X1
;
6285 Crosshair
.AttachedBox
.Point1
.Y
=
6286 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y1
;
6287 AdjustAttachedObjects ();
6288 if (--addedLines
== 0)
6289 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
6292 /* undo the last destructive operation */
6294 SetChangedFlag (true);
6298 switch (GetFunctionID (function
))
6300 /* clear 'undo objects' list */
6302 ClearUndoList (false);
6306 notify_crosshair_change (true);
6310 /* --------------------------------------------------------------------------- */
6312 static const char redo_syntax
[] = "Redo()";
6314 static const char redo_help
[] = "Redo recent \"undo\" operations.";
6316 /* %start-doc actions Redo
6318 This routine allows you to recover from the last undo command. You
6319 might want to do this if you thought that undo was going to revert
6320 something other than what it actually did (in case you are confused
6321 about which operations are un-doable), or if you have been backing up
6322 through a long undo list and over-shoot your stopping point. Any
6323 change that is made since the undo in question will trim the redo
6324 list. For example if you add ten lines, then undo three of them you
6325 could use redo to put them back, but if you move a line on the board
6326 before performing the redo, you will lose the ability to "redo" the
6327 three "undone" lines.
6332 ActionRedo (int argc
, char **argv
, Coord x
, Coord y
)
6334 if (((Settings
.Mode
== POLYGON_MODE
||
6335 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6336 Crosshair
.AttachedPolygon
.PointN
) ||
6337 Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6339 notify_crosshair_change (false);
6342 SetChangedFlag (true);
6343 if (Settings
.Mode
== LINE_MODE
&&
6344 Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
6346 LineType
*line
= g_list_last (CURRENT
->Line
)->data
;
6347 Crosshair
.AttachedLine
.Point1
.X
=
6348 Crosshair
.AttachedLine
.Point2
.X
= line
->Point2
.X
;
6349 Crosshair
.AttachedLine
.Point1
.Y
=
6350 Crosshair
.AttachedLine
.Point2
.Y
= line
->Point2
.Y
;
6354 notify_crosshair_change (true);
6358 /* --------------------------------------------------------------------------- */
6360 static const char polygon_syntax
[] = "Polygon(Close|PreviousPoint)";
6362 static const char polygon_help
[] = "Some polygon related stuff.";
6364 /* %start-doc actions Polygon
6366 Polygons need a special action routine to make life easier.
6371 Creates the final segment of the polygon. This may fail if clipping
6372 to 45 degree lines is switched on, in which case a warning is issued.
6375 Resets the newly entered corner to the previous one. The Undo action
6376 will call Polygon(PreviousPoint) when appropriate to do so.
6383 ActionPolygon (int argc
, char **argv
, Coord x
, Coord y
)
6385 char *function
= ARG (0);
6386 if (function
&& Settings
.Mode
== POLYGON_MODE
)
6388 notify_crosshair_change (false);
6389 switch (GetFunctionID (function
))
6391 /* close open polygon if possible */
6396 /* go back to the previous point */
6397 case F_PreviousPoint
:
6398 GoToPreviousPoint ();
6401 notify_crosshair_change (true);
6406 /* --------------------------------------------------------------------------- */
6408 static const char routestyle_syntax
[] = "RouteStyle(1|2|3|4)";
6410 static const char routestyle_help
[] =
6411 "Copies the indicated routing style into the current sizes.";
6413 /* %start-doc actions RouteStyle
6418 ActionRouteStyle (int argc
, char **argv
, Coord x
, Coord y
)
6420 char *str
= ARG (0);
6421 RouteStyleType
*rts
;
6426 number
= atoi (str
);
6427 if (number
> 0 && number
<= NUM_STYLES
)
6429 rts
= &PCB
->RouteStyle
[number
- 1];
6430 SetLineSize (rts
->Thick
);
6431 SetViaSize (rts
->Diameter
, true);
6432 SetViaDrillingHole (rts
->Hole
, true);
6433 SetKeepawayWidth (rts
->Keepaway
);
6434 hid_action("RouteStylesChanged");
6441 /* --------------------------------------------------------------------------- */
6443 static const char moveobject_syntax
[] = "MoveObject(X,Y,dim)";
6445 static const char moveobject_help
[] = "Moves the object under the crosshair.";
6447 /* %start-doc actions MoveObject
6449 The @code{X} and @code{Y} are treated like @code{delta} is for many
6450 other objects. For each, if it's prefixed by @code{+} or @code{-},
6451 then that amount is relative. Otherwise, it's absolute. Units can be
6452 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
6453 units, currently 1/100 mil.
6458 ActionMoveObject (int argc
, char **argv
, Coord x
, Coord y
)
6460 char *x_str
= ARG (0);
6461 char *y_str
= ARG (1);
6462 char *units
= ARG (2);
6464 bool absolute1
, absolute2
;
6465 void *ptr1
, *ptr2
, *ptr3
;
6468 ny
= GetValue (y_str
, units
, &absolute1
);
6469 nx
= GetValue (x_str
, units
, &absolute2
);
6471 type
= SearchScreen (x
, y
, MOVE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6472 if (type
== NO_TYPE
)
6474 Message (_("Nothing found under crosshair\n"));
6481 Crosshair
.AttachedObject
.RubberbandN
= 0;
6482 if (TEST_FLAG (RUBBERBANDFLAG
, PCB
))
6483 LookupRubberbandLines (type
, ptr1
, ptr2
, ptr3
);
6484 if (type
== ELEMENT_TYPE
)
6485 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
6486 MoveObjectAndRubberband (type
, ptr1
, ptr2
, ptr3
, nx
, ny
);
6487 SetChangedFlag (true);
6491 /* --------------------------------------------------------------------------- */
6493 static const char movetocurrentlayer_syntax
[] =
6494 "MoveToCurrentLayer(Object|SelectedObjects)";
6496 static const char movetocurrentlayer_help
[] =
6497 "Moves objects to the current layer.";
6499 /* %start-doc actions MoveToCurrentLayer
6501 Note that moving an element from a component layer to a solder layer,
6502 or from solder to component, won't automatically flip it. Use the
6503 @code{Flip()} action to do that.
6508 ActionMoveToCurrentLayer (int argc
, char **argv
, Coord x
, Coord y
)
6510 char *function
= ARG (0);
6513 switch (GetFunctionID (function
))
6518 void *ptr1
, *ptr2
, *ptr3
;
6520 gui
->get_coords (_("Select an Object"), &x
, &y
);
6522 SearchScreen (x
, y
, MOVETOLAYER_TYPES
,
6523 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6524 if (MoveObjectToLayer (type
, ptr1
, ptr2
, ptr3
, CURRENT
, false))
6525 SetChangedFlag (true);
6529 case F_SelectedObjects
:
6531 if (MoveSelectedObjectsToLayer (CURRENT
))
6532 SetChangedFlag (true);
6540 static const char setsame_syntax
[] = "SetSame()";
6542 static const char setsame_help
[] =
6543 "Sets current layer and sizes to match indicated item.";
6545 /* %start-doc actions SetSame
6547 When invoked over any line, arc, polygon, or via, this changes the
6548 current layer to be the layer that item is on, and changes the current
6549 sizes (thickness, keepaway, drill, etc) according to that item.
6554 ActionSetSame (int argc
, char **argv
, Coord x
, Coord y
)
6556 void *ptr1
, *ptr2
, *ptr3
;
6558 LayerType
*layer
= CURRENT
;
6560 type
= SearchScreen (x
, y
, CLONE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6561 /* set layer current and size from line or arc */
6565 notify_crosshair_change (false);
6566 Settings
.LineThickness
= ((LineType
*) ptr2
)->Thickness
;
6567 Settings
.Keepaway
= ((LineType
*) ptr2
)->Clearance
/ 2;
6568 layer
= (LayerType
*) ptr1
;
6569 if (Settings
.Mode
!= LINE_MODE
)
6570 SetMode (LINE_MODE
);
6571 notify_crosshair_change (true);
6572 hid_action ("RouteStylesChanged");
6576 notify_crosshair_change (false);
6577 Settings
.LineThickness
= ((ArcType
*) ptr2
)->Thickness
;
6578 Settings
.Keepaway
= ((ArcType
*) ptr2
)->Clearance
/ 2;
6579 layer
= (LayerType
*) ptr1
;
6580 if (Settings
.Mode
!= ARC_MODE
)
6582 notify_crosshair_change (true);
6583 hid_action ("RouteStylesChanged");
6587 layer
= (LayerType
*) ptr1
;
6591 notify_crosshair_change (false);
6592 Settings
.ViaThickness
= ((PinType
*) ptr2
)->Thickness
;
6593 Settings
.ViaDrillingHole
= ((PinType
*) ptr2
)->DrillingHole
;
6594 Settings
.Keepaway
= ((PinType
*) ptr2
)->Clearance
/ 2;
6595 if (Settings
.Mode
!= VIA_MODE
)
6597 notify_crosshair_change (true);
6598 hid_action ("RouteStylesChanged");
6604 if (layer
!= CURRENT
)
6606 ChangeGroupVisibility (GetLayerNumber (PCB
->Data
, layer
), true, true);
6613 /* --------------------------------------------------------------------------- */
6615 static const char setflag_syntax
[] =
6616 "SetFlag(Object|Selected|SelectedObjects, flag)\n"
6617 "SetFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6618 "SetFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6619 "SetFlag(SelectedElements, flag)\n"
6620 "flag = square | octagon | thermal | join";
6622 static const char setflag_help
[] = "Sets flags on objects.";
6624 /* %start-doc actions SetFlag
6626 Turns the given flag on, regardless of its previous setting. See
6630 SetFlag(SelectedPins,thermal)
6636 ActionSetFlag (int argc
, char **argv
, Coord x
, Coord y
)
6638 char *function
= ARG (0);
6639 char *flag
= ARG (1);
6640 ChangeFlag (function
, flag
, 1, "SetFlag");
6644 /* --------------------------------------------------------------------------- */
6646 static const char clrflag_syntax
[] =
6647 "ClrFlag(Object|Selected|SelectedObjects, flag)\n"
6648 "ClrFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6649 "ClrFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6650 "ClrFlag(SelectedElements, flag)\n"
6651 "flag = square | octagon | thermal | join";
6653 static const char clrflag_help
[] = "Clears flags on objects.";
6655 /* %start-doc actions ClrFlag
6657 Turns the given flag off, regardless of its previous setting. See
6661 ClrFlag(SelectedLines,join)
6667 ActionClrFlag (int argc
, char **argv
, Coord x
, Coord y
)
6669 char *function
= ARG (0);
6670 char *flag
= ARG (1);
6671 ChangeFlag (function
, flag
, 0, "ClrFlag");
6675 /* --------------------------------------------------------------------------- */
6677 static const char changeflag_syntax
[] =
6678 "ChangeFlag(Object|Selected|SelectedObjects, flag, value)\n"
6679 "ChangeFlag(SelectedLines|SelectedPins|SelectedVias, flag, value)\n"
6680 "ChangeFlag(SelectedPads|SelectedTexts|SelectedNames, flag, value)\n"
6681 "ChangeFlag(SelectedElements, flag, value)\n"
6682 "flag = square | octagon | thermal | join\n"
6685 static const char changeflag_help
[] = "Sets or clears flags on objects.";
6687 /* %start-doc actions ChangeFlag
6689 Toggles the given flag on the indicated object(s). The flag may be
6690 one of the flags listed above (square, octagon, thermal, join). The
6691 value may be the number 0 or 1. If the value is 0, the flag is
6692 cleared. If the value is 1, the flag is set.
6697 ActionChangeFlag (int argc
, char **argv
, Coord x
, Coord y
)
6699 char *function
= ARG (0);
6700 char *flag
= ARG (1);
6701 int value
= argc
> 2 ? atoi (argv
[2]) : -1;
6702 if (value
!= 0 && value
!= 1)
6705 ChangeFlag (function
, flag
, value
, "ChangeFlag");
6711 ChangeFlag (char *what
, char *flag_name
, int value
, char *cmd_name
)
6713 bool (*set_object
) (int, void *, void *, void *);
6714 bool (*set_selected
) (int);
6716 if (NSTRCMP (flag_name
, "square") == 0)
6718 set_object
= value
? SetObjectSquare
: ClrObjectSquare
;
6719 set_selected
= value
? SetSelectedSquare
: ClrSelectedSquare
;
6721 else if (NSTRCMP (flag_name
, "octagon") == 0)
6723 set_object
= value
? SetObjectOctagon
: ClrObjectOctagon
;
6724 set_selected
= value
? SetSelectedOctagon
: ClrSelectedOctagon
;
6726 else if (NSTRCMP (flag_name
, "join") == 0)
6728 /* Note: these are backwards, because the flag is "clear" but
6729 the command is "join". */
6730 set_object
= value
? ClrObjectJoin
: SetObjectJoin
;
6731 set_selected
= value
? ClrSelectedJoin
: SetSelectedJoin
;
6735 Message (_("%s(): Flag \"%s\" is not valid\n"), cmd_name
, flag_name
);
6739 switch (GetFunctionID (what
))
6744 void *ptr1
, *ptr2
, *ptr3
;
6747 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
6748 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6749 if (TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
6750 Message (_("Sorry, the object is locked\n"));
6751 if (set_object (type
, ptr1
, ptr2
, ptr3
))
6752 SetChangedFlag (true);
6756 case F_SelectedVias
:
6757 if (set_selected (VIA_TYPE
))
6758 SetChangedFlag (true);
6761 case F_SelectedPins
:
6762 if (set_selected (PIN_TYPE
))
6763 SetChangedFlag (true);
6766 case F_SelectedPads
:
6767 if (set_selected (PAD_TYPE
))
6768 SetChangedFlag (true);
6771 case F_SelectedLines
:
6772 if (set_selected (LINE_TYPE
))
6773 SetChangedFlag (true);
6776 case F_SelectedTexts
:
6777 if (set_selected (TEXT_TYPE
))
6778 SetChangedFlag (true);
6781 case F_SelectedNames
:
6782 if (set_selected (ELEMENTNAME_TYPE
))
6783 SetChangedFlag (true);
6786 case F_SelectedElements
:
6787 if (set_selected (ELEMENT_TYPE
))
6788 SetChangedFlag (true);
6792 case F_SelectedObjects
:
6793 if (set_selected (CHANGESIZE_TYPES
))
6794 SetChangedFlag (true);
6799 /* --------------------------------------------------------------------------- */
6801 static const char executefile_syntax
[] = "ExecuteFile(filename)";
6803 static const char executefile_help
[] = "Run actions from the given file.";
6805 /* %start-doc actions ExecuteFile
6807 Lines starting with @code{#} are ignored.
6812 ActionExecuteFile (int argc
, char **argv
, Coord x
, Coord y
)
6821 AFAIL (executefile
);
6825 if ((fp
= fopen (fname
, "r")) == NULL
)
6827 fprintf (stderr
, _("Could not open actions file \"%s\".\n"), fname
);
6832 defer_needs_update
= 0;
6833 while (fgets (line
, sizeof (line
), fp
) != NULL
)
6838 /* eat the trailing newline */
6839 while (*sp
&& *sp
!= '\r' && *sp
!= '\n')
6843 /* eat leading spaces and tabs */
6845 while (*sp
&& (*sp
== ' ' || *sp
== '\t'))
6849 * if we have anything left and its not a comment line
6853 if (*sp
&& *sp
!= '#')
6855 /*Message ("%s : line %-3d : \"%s\"\n", fname, n, sp);*/
6856 hid_parse_actions (sp
);
6861 if (defer_needs_update
)
6863 IncrementUndoSerialNumber ();
6864 gui
->invalidate_all ();
6870 /* --------------------------------------------------------------------------- */
6873 ActionPSCalib (int argc
, char **argv
, Coord x
, Coord y
)
6875 HID
*ps
= hid_find_exporter ("ps");
6876 ps
->calibrate (0.0,0.0);
6880 /* --------------------------------------------------------------------------- */
6882 static ElementType
*element_cache
= NULL
;
6884 static ElementType
*
6885 find_element_by_refdes (char *refdes
)
6888 && NAMEONPCB_NAME(element_cache
)
6889 && strcmp (NAMEONPCB_NAME(element_cache
), refdes
) == 0)
6890 return element_cache
;
6892 ELEMENT_LOOP (PCB
->Data
);
6894 if (NAMEONPCB_NAME(element
)
6895 && strcmp (NAMEONPCB_NAME(element
), refdes
) == 0)
6897 element_cache
= element
;
6898 return element_cache
;
6905 static AttributeType
*
6906 lookup_attr (AttributeListType
*list
, const char *name
)
6909 for (i
=0; i
<list
->Number
; i
++)
6910 if (strcmp (list
->List
[i
].name
, name
) == 0)
6911 return & list
->List
[i
];
6916 delete_attr (AttributeListType
*list
, AttributeType
*attr
)
6918 int idx
= attr
- list
->List
;
6919 if (idx
< 0 || idx
>= list
->Number
)
6921 if (list
->Number
- idx
> 1)
6922 memmove (attr
, attr
+1, (list
->Number
- idx
- 1) * sizeof(AttributeType
));
6926 /* ---------------------------------------------------------------- */
6927 static const char elementlist_syntax
[] = "ElementList(Start|Done|Need,<refdes>,<footprint>,<value>)";
6929 static const char elementlist_help
[] = "Adds the given element if it doesn't already exist.";
6931 /* %start-doc actions elementlist
6936 Indicates the start of an element list; call this before any Need
6940 Searches the board for an element with a matching refdes.
6942 If found, the value and footprint are updated.
6944 If not found, a new element is created with the given footprint and value.
6947 Compares the list of elements needed since the most recent
6948 @code{start} with the list of elements actually on the board. Any
6949 elements that weren't listed are selected, so that the user may delete
6956 static int number_of_footprints_not_found
;
6959 parse_layout_attribute_units (char *name
, int def
)
6961 const char *as
= AttributeGet (PCB
, name
);
6964 return GetValue (as
, NULL
, NULL
);
6968 ActionElementList (int argc
, char **argv
, Coord x
, Coord y
)
6970 ElementType
*e
= NULL
;
6971 char *refdes
, *value
, *footprint
, *old
;
6973 char *function
= argv
[0];
6976 printf("Entered ActionElementList, executing function %s\n", function
);
6979 if (strcasecmp (function
, "start") == 0)
6981 ELEMENT_LOOP (PCB
->Data
);
6983 CLEAR_FLAG (FOUNDFLAG
, element
);
6986 element_cache
= NULL
;
6987 number_of_footprints_not_found
= 0;
6991 if (strcasecmp (function
, "done") == 0)
6993 ELEMENT_LOOP (PCB
->Data
);
6995 if (TEST_FLAG (FOUNDFLAG
, element
))
6997 CLEAR_FLAG (FOUNDFLAG
, element
);
6999 else if (! EMPTY_STRING_P (NAMEONPCB_NAME (element
)))
7001 /* Unnamed elements should remain untouched */
7002 SET_FLAG (SELECTEDFLAG
, element
);
7006 if (number_of_footprints_not_found
> 0)
7007 gui
->confirm_dialog ("Not all requested footprints were found.\n"
7008 "See the message log for details",
7013 if (strcasecmp (function
, "need") != 0)
7014 AFAIL (elementlist
);
7017 AFAIL (elementlist
);
7026 args
[0] = footprint
;
7031 printf(" ... footprint = %s\n", footprint
);
7032 printf(" ... refdes = %s\n", refdes
);
7033 printf(" ... value = %s\n", value
);
7036 e
= find_element_by_refdes (refdes
);
7043 printf(" ... Footprint not on board, need to add it.\n");
7045 /* Not on board, need to add it. */
7046 if (LoadFootprint(argc
, args
, x
, y
))
7048 number_of_footprints_not_found
++;
7052 nx
= PCB
->MaxWidth
/ 2;
7053 ny
= PCB
->MaxHeight
/ 2;
7054 d
= MIN (PCB
->MaxWidth
, PCB
->MaxHeight
) / 10;
7056 nx
= parse_layout_attribute_units ("import::newX", nx
);
7057 ny
= parse_layout_attribute_units ("import::newY", ny
);
7058 d
= parse_layout_attribute_units ("import::disperse", d
);
7062 nx
+= rand () % (d
*2) - d
;
7063 ny
+= rand () % (d
*2) - d
;
7068 if (nx
>= PCB
->MaxWidth
)
7069 nx
= PCB
->MaxWidth
- 1;
7072 if (ny
>= PCB
->MaxHeight
)
7073 ny
= PCB
->MaxHeight
- 1;
7075 /* Place components onto center of board. */
7076 if (CopyPastebufferToLayout (nx
, ny
))
7077 SetChangedFlag (true);
7080 else if (e
&& strcmp (DESCRIPTION_NAME(e
), footprint
) != 0)
7083 printf(" ... Footprint on board, but different from footprint loaded.\n");
7089 /* Different footprint, we need to swap them out. */
7090 if (LoadFootprint(argc
, args
, x
, y
))
7092 number_of_footprints_not_found
++;
7096 er
= ElementOrientation (e
);
7097 pe
= PASTEBUFFER
->Data
->Element
->data
;
7099 MirrorElementCoordinates (PASTEBUFFER
->Data
, pe
, pe
->MarkY
*2 - PCB
->MaxHeight
);
7100 pr
= ElementOrientation (pe
);
7106 RotateElementLowLevel (PASTEBUFFER
->Data
, pe
, pe
->MarkX
, pe
->MarkY
, (er
-pr
+4)%4);
7108 for (i
=0; i
<MAX_ELEMENTNAMES
; i
++)
7110 pe
->Name
[i
].X
= e
->Name
[i
].X
- mx
+ pe
->MarkX
;
7111 pe
->Name
[i
].Y
= e
->Name
[i
].Y
- my
+ pe
->MarkY
;
7112 pe
->Name
[i
].Direction
= e
->Name
[i
].Direction
;
7113 pe
->Name
[i
].Scale
= e
->Name
[i
].Scale
;
7118 if (CopyPastebufferToLayout (mx
, my
))
7119 SetChangedFlag (true);
7122 /* Now reload footprint */
7123 element_cache
= NULL
;
7124 e
= find_element_by_refdes (refdes
);
7126 old
= ChangeElementText (PCB
, PCB
->Data
, e
, NAMEONPCB_INDEX
, strdup (refdes
));
7129 old
= ChangeElementText (PCB
, PCB
->Data
, e
, VALUE_INDEX
, strdup (value
));
7133 SET_FLAG (FOUNDFLAG
, e
);
7136 printf(" ... Leaving ActionElementList.\n");
7142 /* ---------------------------------------------------------------- */
7143 static const char elementsetattr_syntax
[] = "ElementSetAttr(refdes,name[,value])";
7145 static const char elementsetattr_help
[] = "Sets or clears an element-specific attribute.";
7147 /* %start-doc actions elementsetattr
7149 If a value is specified, the named attribute is added (if not already
7150 present) or changed (if it is) to the given value. If the value is
7151 not specified, the given attribute is removed if present.
7156 ActionElementSetAttr (int argc
, char **argv
, Coord x
, Coord y
)
7158 ElementType
*e
= NULL
;
7159 char *refdes
, *name
, *value
;
7160 AttributeType
*attr
;
7164 AFAIL (changepinname
);
7171 ELEMENT_LOOP (PCB
->Data
);
7173 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
7183 Message(_("Cannot change attribute of %s - element not found\n"), refdes
);
7187 attr
= lookup_attr (&e
->Attributes
, name
);
7192 attr
->value
= strdup (value
);
7194 if (attr
&& ! value
)
7196 delete_attr (& e
->Attributes
, attr
);
7200 CreateNewAttribute (& e
->Attributes
, name
, value
);
7206 /* ---------------------------------------------------------------- */
7207 static const char execcommand_syntax
[] = "ExecCommand(command)";
7209 static const char execcommand_help
[] = "Runs a command.";
7211 /* %start-doc actions execcommand
7213 Runs the given command, which is a system executable.
7218 ActionExecCommand (int argc
, char **argv
, Coord x
, Coord y
)
7224 AFAIL (execcommand
);
7229 if (system (command
))
7234 /* ---------------------------------------------------------------- */
7237 pcb_spawnvp (char **argv
)
7239 #ifdef HAVE__SPAWNVP
7240 int result
= _spawnvp (_P_WAIT
, argv
[0], (const char * const *) argv
);
7251 Message(_("Cannot fork!"));
7257 execvp (argv
[0], argv
);
7270 /* ---------------------------------------------------------------- */
7272 * Creates a new temporary file name. Hopefully the operating system
7273 * provides a mkdtemp() function to securily create a temporary
7274 * directory with mode 0700. If so then that directory is created and
7275 * the returned string is made up of the directory plus the name
7276 * variable. For example:
7278 * tempfile_name_new ("myfile") might return
7279 * "/var/tmp/pcb.123456/myfile".
7281 * If mkdtemp() is not available then 'name' is ignored and the
7282 * insecure tmpnam() function is used.
7284 * Files/names created with tempfile_name_new() should be unlinked
7285 * with tempfile_unlink to make sure the temporary directory is also
7286 * removed when mkdtemp() is used.
7289 tempfile_name_new (char * name
)
7291 char *tmpfile
= NULL
;
7293 char *tmpdir
, *mytmpdir
;
7297 assert ( name
!= NULL
);
7300 #define TEMPLATE "pcb.XXXXXXXX"
7303 tmpdir
= getenv ("TMPDIR");
7305 /* FIXME -- what about win32? */
7306 if (tmpdir
== NULL
) {
7310 mytmpdir
= (char *) malloc (sizeof(char) *
7315 if (mytmpdir
== NULL
) {
7316 fprintf (stderr
, "%s(): malloc failed()\n", __FUNCTION__
);
7321 (void)strcat (mytmpdir
, tmpdir
);
7322 (void)strcat (mytmpdir
, PCB_DIR_SEPARATOR_S
);
7323 (void)strcat (mytmpdir
, TEMPLATE
);
7324 if (mkdtemp (mytmpdir
) == NULL
) {
7325 fprintf (stderr
, "%s(): mkdtemp (\"%s\") failed\n", __FUNCTION__
, mytmpdir
);
7331 len
= strlen (mytmpdir
) + /* the temp directory name */
7332 1 + /* the directory sep. */
7333 strlen (name
) + /* the file name */
7334 1 /* the \0 termination */
7337 tmpfile
= (char *) malloc (sizeof (char) * len
);
7340 (void)strcat (tmpfile
, mytmpdir
);
7341 (void)strcat (tmpfile
, PCB_DIR_SEPARATOR_S
);
7342 (void)strcat (tmpfile
, name
);
7348 * tmpnam() uses a static buffer so strdup() the result right away
7349 * in case someone decides to create multiple temp names.
7351 tmpfile
= strdup (tmpnam (NULL
));
7354 /* Guile doesn't like \ separators */
7356 for (c
= tmpfile
; *c
; c
++)
7366 /* ---------------------------------------------------------------- */
7368 * Unlink a temporary file. If we have mkdtemp() then our temp file
7369 * lives in a temporary directory and we need to remove that directory
7373 tempfile_unlink (char * name
)
7376 /* SDB says: Want to keep old temp files for examiniation when debugging */
7385 /* it is possible that the file was never created so it is OK if the
7388 /* now figure out the directory name to remove */
7389 e
= strlen (name
) - 1;
7390 while (e
> 0 && name
[e
] != PCB_DIR_SEPARATOR_C
) {e
--;}
7392 dname
= strdup (name
);
7396 * at this point, e *should* point to the end of the directory part
7397 * but lets make sure.
7400 rc2
= rmdir (dname
);
7406 fprintf (stderr
, _("%s(): Unable to determine temp directory name from the temp file\n"),
7408 fprintf (stderr
, "%s(): \"%s\"\n",
7409 __FUNCTION__
, name
);
7413 /* name was allocated with malloc */
7418 * FIXME - should also return -1 if the temp file exists and was not
7426 int rc
= unlink (name
);
7429 fprintf (stderr
, _("Failed to unlink \"%s\"\n"), name
);
7440 /* ---------------------------------------------------------------- */
7441 static const char import_syntax
[] =
7443 "Import([gnetlist|make[,source,source,...]])\n"
7444 "Import(setnewpoint[,(mark|center|X,Y)])\n"
7445 "Import(setdisperse,D,units)\n";
7447 static const char import_help
[] = "Import schematics.";
7449 /* %start-doc actions Import
7451 Imports element and netlist data from the schematics (or some other
7452 source). The first parameter, which is optional, is the mode. If not
7453 specified, the @code{import::mode} attribute in the PCB is used.
7454 @code{gnetlist} means gnetlist is used to obtain the information from
7455 the schematics. @code{make} invokes @code{make}, assuming the user
7456 has a @code{Makefile} in the current directory. The @code{Makefile}
7457 will be invoked with the following variables set:
7462 The name of the .pcb file
7465 A space-separated list of source files
7468 The name of the file in which to put the command script, which may
7469 contain any @pcb{} actions. By default, this is a temporary file
7470 selected by @pcb{}, but if you specify an @code{import::outfile}
7471 attribute, that file name is used instead (and not automatically
7472 deleted afterwards).
7476 The target specified to be built is the first of these that apply:
7481 The target specified by an @code{import::target} attribute.
7484 The output file specified by an @code{import::outfile} attribute.
7487 If nothing else is specified, the target is @code{pcb_import}.
7491 If you specify an @code{import::makefile} attribute, then "-f <that
7492 file>" will be added to the command line.
7494 If you specify the mode, you may also specify the source files
7495 (schematics). If you do not specify any, the list of schematics is
7496 obtained by reading the @code{import::src@var{N}} attributes (like
7497 @code{import::src0}, @code{import::src1}, etc).
7499 For compatibility with future extensions to the import file format,
7500 the generated file @emph{must not} start with the two characters
7503 If a temporary file is needed the @code{TMPDIR} environment variable
7504 is used to select its location.
7506 Note that the programs @code{gnetlist} and @code{make} may be
7507 overridden by the user via the @code{make-program} and @code{gnetlist}
7508 @code{pcb} settings (i.e. in @code{~/.pcb/settings} or on the command
7511 If @pcb{} cannot determine which schematic(s) to import from, the GUI
7512 is called to let user choose (see @code{ImportGUI()}).
7514 Note that Import() doesn't delete anything - after an Import, elements
7515 which shouldn't be on the board are selected and may be removed once
7516 it's determined that the deletion is appropriate.
7518 If @code{Import()} is called with @code{setnewpoint}, then the location
7519 of new components can be specified. This is where parts show up when
7520 they're added to the board. The default is the center of the board.
7524 @item Import(setnewpoint)
7526 Prompts the user to click on the board somewhere, uses that point. If
7527 called by a hotkey, uses the current location of the crosshair.
7529 @item Import(setnewpoint,mark)
7531 Uses the location of the mark. If no mark is present, the point is
7534 @item Import(setnewpoint,center)
7536 Resets the point to the center of the board.
7538 @item Import(setnewpoint,X,Y,units)
7540 Sets the point to the specific coordinates given. Example:
7541 @code{Import(setnewpoint,50,25,mm)}
7545 Note that the X and Y locations are stored in attributes named
7546 @code{import::newX} and @code{import::newY} so you could change them
7547 manually if you wished.
7549 Calling @code{Import(setdisperse,D,units)} sets how much the newly
7550 placed elements are dispersed relative to the set point. For example,
7551 @code{Import(setdisperse,10,mm)} will offset each part randomly up to
7552 10mm away from the point. The default dispersion is 1/10th of the
7553 smallest board dimension. Dispersion is saved in the
7554 @code{import::disperse} attribute.
7559 ActionImport (int argc
, char **argv
, Coord x
, Coord y
)
7562 char **sources
= NULL
;
7566 printf("ActionImport: =========== Entering ActionImport ============\n");
7571 if (mode
&& strcasecmp (mode
, "setdisperse") == 0)
7580 const char *as
= AttributeGet (PCB
, "import::disperse");
7581 ds
= gui
->prompt_for(_("Enter dispersion:"), as
? as
: "0");
7585 sprintf(buf
, "%s%s", ds
, units
);
7586 AttributePut (PCB
, "import::disperse", buf
);
7589 AttributePut (PCB
, "import::disperse", ds
);
7590 if (ARG (1) == NULL
)
7595 if (mode
&& strcasecmp (mode
, "setnewpoint") == 0)
7597 const char *xs
, *ys
, *units
;
7607 gui
->get_coords (_("Click on a location"), &x
, &y
);
7609 else if (strcasecmp (xs
, "center") == 0)
7611 AttributeRemove (PCB
, "import::newX");
7612 AttributeRemove (PCB
, "import::newY");
7615 else if (strcasecmp (xs
, "mark") == 0)
7625 x
= GetValue (xs
, units
, NULL
);
7626 y
= GetValue (ys
, units
, NULL
);
7630 Message (_("Bad syntax for Import(setnewpoint)"));
7634 pcb_sprintf (buf
, "%$ms", x
);
7635 AttributePut (PCB
, "import::newX", buf
);
7636 pcb_sprintf (buf
, "%$ms", y
);
7637 AttributePut (PCB
, "import::newY", buf
);
7642 mode
= AttributeGet (PCB
, "import::mode");
7649 nsources
= argc
- 1;
7660 sprintf(sname
, "import::src%d", nsources
);
7661 src
= AttributeGet (PCB
, sname
);
7666 sources
= (char **) malloc ((nsources
+ 1) * sizeof (char *));
7670 sprintf(sname
, "import::src%d", nsources
);
7671 src
= AttributeGet (PCB
, sname
);
7672 sources
[nsources
] = src
;
7679 /* Replace .pcb with .sch and hope for the best. */
7680 char *pcbname
= PCB
->Filename
;
7682 char *dot
, *slash
, *bslash
;
7685 return hid_action("ImportGUI");
7687 schname
= (char *) malloc (strlen(pcbname
) + 5);
7688 strcpy (schname
, pcbname
);
7689 dot
= strchr (schname
, '.');
7690 slash
= strchr (schname
, '/');
7691 bslash
= strchr (schname
, '\\');
7692 if (dot
&& slash
&& dot
< slash
)
7694 if (dot
&& bslash
&& dot
< bslash
)
7698 strcat (schname
, ".sch");
7700 if (access (schname
, F_OK
))
7703 return hid_action("ImportGUI");
7706 sources
= (char **) malloc (2 * sizeof (char *));
7707 sources
[0] = schname
;
7712 if (strcasecmp (mode
, "gnetlist") == 0)
7714 char *tmpfile
= tempfile_name_new ("gnetlist_output");
7718 if (tmpfile
== NULL
) {
7719 Message (_("Could not create temp file"));
7723 cmd
= (char **) malloc ((7 + nsources
) * sizeof (char *));
7724 cmd
[0] = Settings
.GnetlistProgram
;
7730 for (i
=0; i
<nsources
; i
++)
7731 cmd
[6+i
] = sources
[i
];
7732 cmd
[6+nsources
] = NULL
;
7735 printf("ActionImport: =========== About to run gnetlist ============\n");
7736 printf("%s %s %s %s %s %s %s ...\n",
7737 cmd
[0], cmd
[1], cmd
[2], cmd
[3], cmd
[4], cmd
[5], cmd
[6]);
7740 if (pcb_spawnvp (cmd
))
7747 printf("ActionImport: =========== About to run ActionExecuteFile, file = %s ============\n", tmpfile
);
7752 ActionExecuteFile (1, cmd
, 0, 0);
7755 tempfile_unlink (tmpfile
);
7757 else if (strcasecmp (mode
, "make") == 0)
7759 int must_free_tmpfile
= 0;
7765 char *user_outfile
= NULL
;
7766 char *user_makefile
= NULL
;
7767 char *user_target
= NULL
;
7770 user_outfile
= AttributeGet (PCB
, "import::outfile");
7771 user_makefile
= AttributeGet (PCB
, "import::makefile");
7772 user_target
= AttributeGet (PCB
, "import::target");
7773 if (user_outfile
&& !user_target
)
7774 user_target
= user_outfile
;
7777 tmpfile
= user_outfile
;
7780 tmpfile
= tempfile_name_new ("gnetlist_output");
7781 if (tmpfile
== NULL
) {
7782 Message (_("Could not create temp file"));
7785 must_free_tmpfile
= 1;
7788 srclen
= sizeof("SRCLIST=") + 2;
7789 for (i
=0; i
<nsources
; i
++)
7790 srclen
+= strlen (sources
[i
]) + 2;
7791 srclist
= (char *) malloc (srclen
);
7792 strcpy (srclist
, "SRCLIST=");
7793 for (i
=0; i
<nsources
; i
++)
7796 strcat (srclist
, " ");
7797 strcat (srclist
, sources
[i
]);
7800 cmd
[0] = Settings
.MakeProgram
;
7802 cmd
[2] = Concat ("PCB=", PCB
->Filename
, NULL
);
7804 cmd
[4] = Concat ("OUT=", tmpfile
, NULL
);
7809 cmd
[i
++] = user_makefile
;
7811 cmd
[i
++] = user_target
? user_target
: (char *)"pcb_import";
7814 if (pcb_spawnvp (cmd
))
7816 if (must_free_tmpfile
)
7826 ActionExecuteFile (1, cmd
, 0, 0);
7831 if (must_free_tmpfile
)
7832 tempfile_unlink (tmpfile
);
7836 Message (_("Unknown import mode: %s\n"), mode
);
7841 AddAllRats (false, NULL
);
7844 printf("ActionImport: =========== Leaving ActionImport ============\n");
7850 /* ------------------------------------------------------------ */
7852 static const char attributes_syntax
[] =
7853 "Attributes(Layout|Layer|Element)\n"
7854 "Attributes(Layer,layername)";
7856 static const char attributes_help
[] =
7857 "Let the user edit the attributes of the layout, current or given\n"
7858 "layer, or selected element.";
7860 /* %start-doc actions Attributes
7862 This just pops up a dialog letting the user edit the attributes of the
7863 pcb, an element, or a layer.
7869 ActionAttributes (int argc
, char **argv
, Coord x
, Coord y
)
7871 char *function
= ARG (0);
7872 char *layername
= ARG (1);
7878 if (!gui
->edit_attributes
)
7880 Message (_("This GUI doesn't support Attribute Editing\n"));
7884 switch (GetFunctionID (function
))
7888 gui
->edit_attributes("Layout Attributes", &(PCB
->Attributes
));
7894 LayerType
*layer
= CURRENT
;
7899 for (i
=0; i
<max_copper_layer
; i
++)
7900 if (strcmp (PCB
->Data
->Layer
[i
].Name
, layername
) == 0)
7902 layer
= & (PCB
->Data
->Layer
[i
]);
7907 Message (_("No layer named %s\n"), layername
);
7911 buf
= (char *) malloc (strlen (layer
->Name
) + strlen ("Layer X Attributes"));
7912 sprintf (buf
, "Layer %s Attributes", layer
->Name
);
7913 gui
->edit_attributes(buf
, &(layer
->Attributes
));
7921 ElementType
*e
= NULL
;
7922 ELEMENT_LOOP (PCB
->Data
);
7924 if (TEST_FLAG (SELECTEDFLAG
, element
))
7933 Message (_("Too many elements selected\n"));
7939 gui
->get_coords (_("Click on an element"), &x
, &y
);
7941 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
7942 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
7943 e
= (ElementType
*) ptrtmp
;
7946 Message (_("No element found there\n"));
7951 if (NAMEONPCB_NAME(e
))
7953 buf
= (char *) malloc (strlen (NAMEONPCB_NAME(e
)) + strlen ("Element X Attributes"));
7954 sprintf(buf
, "Element %s Attributes", NAMEONPCB_NAME(e
));
7958 buf
= strdup ("Unnamed Element Attributes");
7960 gui
->edit_attributes(buf
, &(e
->Attributes
));
7972 /* --------------------------------------------------------------------------- */
7974 HID_Action action_action_list
[] = {
7975 {"AddRats", 0, ActionAddRats
,
7976 addrats_help
, addrats_syntax
}
7978 {"Attributes", 0, ActionAttributes
,
7979 attributes_help
, attributes_syntax
}
7981 {"Atomic", 0, ActionAtomic
,
7982 atomic_help
, atomic_syntax
}
7984 {"AutoPlaceSelected", 0, ActionAutoPlaceSelected
,
7985 autoplace_help
, autoplace_syntax
}
7987 {"AutoRoute", 0, ActionAutoRoute
,
7988 autoroute_help
, autoroute_syntax
}
7990 {"ChangeClearSize", 0, ActionChangeClearSize
,
7991 changeclearsize_help
, changeclearsize_syntax
}
7993 {"ChangeDrillSize", 0, ActionChange2ndSize
,
7994 changedrillsize_help
, changedrillsize_syntax
}
7996 {"ChangeHole", 0, ActionChangeHole
,
7997 changehold_help
, changehold_syntax
}
7999 {"ChangeJoin", 0, ActionChangeJoin
,
8000 changejoin_help
, changejoin_syntax
}
8002 {"ChangeName", 0, ActionChangeName
,
8003 changename_help
, changename_syntax
}
8005 {"ChangePaste", 0, ActionChangePaste
,
8006 changepaste_help
, changepaste_syntax
}
8008 {"ChangePinName", 0, ActionChangePinName
,
8009 changepinname_help
, changepinname_syntax
}
8011 {"ChangeSize", 0, ActionChangeSize
,
8012 changesize_help
, changesize_syntax
}
8014 {"ChangeSquare", 0, ActionChangeSquare
,
8015 changesquare_help
, changesquare_syntax
}
8017 {"ChangeOctagon", 0, ActionChangeOctagon
,
8018 changeoctagon_help
, changeoctagon_syntax
}
8020 {"ClearSquare", 0, ActionClearSquare
,
8021 clearsquare_help
, clearsquare_syntax
}
8023 {"ClearOctagon", 0, ActionClearOctagon
,
8024 clearoctagon_help
, clearoctagon_syntax
}
8026 {"Connection", 0, ActionConnection
,
8027 connection_help
, connection_syntax
}
8029 {"Delete", 0, ActionDelete
,
8030 delete_help
, delete_syntax
}
8032 {"DeleteRats", 0, ActionDeleteRats
,
8033 deleterats_help
, deleterats_syntax
}
8035 {"DisperseElements", 0, ActionDisperseElements
,
8036 disperseelements_help
, disperseelements_syntax
}
8038 {"Display", 0, ActionDisplay
,
8039 display_help
, display_syntax
}
8041 {"DRC", 0, ActionDRCheck
,
8042 drc_help
, drc_syntax
}
8044 {"DumpLibrary", 0, ActionDumpLibrary
,
8045 dumplibrary_help
, dumplibrary_syntax
}
8047 {"ExecuteFile", 0, ActionExecuteFile
,
8048 executefile_help
, executefile_syntax
}
8050 {"Flip", N_("Click on Object or Flip Point"), ActionFlip
,
8051 flip_help
, flip_syntax
}
8053 {"LoadFrom", 0, ActionLoadFrom
,
8054 loadfrom_help
, loadfrom_syntax
}
8056 {"MarkCrosshair", 0, ActionMarkCrosshair
,
8057 markcrosshair_help
, markcrosshair_syntax
}
8059 {"Message", 0, ActionMessage
,
8060 message_help
, message_syntax
}
8062 {"MinMaskGap", 0, ActionMinMaskGap
,
8063 minmaskgap_help
, minmaskgap_syntax
}
8065 {"MinClearGap", 0, ActionMinClearGap
,
8066 mincleargap_help
, mincleargap_syntax
}
8068 {"Mode", 0, ActionMode
,
8069 mode_help
, mode_syntax
}
8071 {"MorphPolygon", 0, ActionMorphPolygon
,
8072 morphpolygon_help
, morphpolygon_syntax
}
8074 {"PasteBuffer", 0, ActionPasteBuffer
,
8075 pastebuffer_help
, pastebuffer_syntax
}
8077 {"Quit", 0, ActionQuit
,
8078 quit_help
, quit_syntax
}
8080 {"RemoveSelected", 0, ActionRemoveSelected
,
8081 removeselected_help
, removeselected_syntax
}
8083 {"Renumber", 0, ActionRenumber
,
8084 renumber_help
, renumber_syntax
}
8086 {"RipUp", 0, ActionRipUp
,
8087 ripup_help
, ripup_syntax
}
8089 {"Select", 0, ActionSelect
,
8090 select_help
, select_syntax
}
8092 {"Unselect", 0, ActionUnselect
,
8093 unselect_help
, unselect_syntax
}
8095 {"SaveSettings", 0, ActionSaveSettings
,
8096 savesettings_help
, savesettings_syntax
}
8098 {"SaveTo", 0, ActionSaveTo
,
8099 saveto_help
, saveto_syntax
}
8101 {"SetSquare", 0, ActionSetSquare
,
8102 setsquare_help
, setsquare_syntax
}
8104 {"SetOctagon", 0, ActionSetOctagon
,
8105 setoctagon_help
, setoctagon_syntax
}
8107 {"SetThermal", 0, ActionSetThermal
,
8108 setthermal_help
, setthermal_syntax
}
8110 {"SetValue", 0, ActionSetValue
,
8111 setvalue_help
, setvalue_syntax
}
8113 {"ToggleHideName", 0, ActionToggleHideName
,
8114 togglehidename_help
, togglehidename_syntax
}
8116 {"Undo", 0, ActionUndo
,
8117 undo_help
, undo_syntax
}
8119 {"Redo", 0, ActionRedo
,
8120 redo_help
, redo_syntax
}
8122 {"SetSame", N_("Select item to use attributes from"), ActionSetSame
,
8123 setsame_help
, setsame_syntax
}
8125 {"SetFlag", 0, ActionSetFlag
,
8126 setflag_help
, setflag_syntax
}
8128 {"ClrFlag", 0, ActionClrFlag
,
8129 clrflag_help
, clrflag_syntax
}
8131 {"ChangeFlag", 0, ActionChangeFlag
,
8132 changeflag_help
, changeflag_syntax
}
8134 {"Polygon", 0, ActionPolygon
,
8135 polygon_help
, polygon_syntax
}
8137 {"RouteStyle", 0, ActionRouteStyle
,
8138 routestyle_help
, routestyle_syntax
}
8140 {"MoveObject", N_("Select an Object"), ActionMoveObject
,
8141 moveobject_help
, moveobject_syntax
}
8143 {"MoveToCurrentLayer", 0, ActionMoveToCurrentLayer
,
8144 movetocurrentlayer_help
, movetocurrentlayer_syntax
}
8146 {"New", 0, ActionNew
,
8147 new_help
, new_syntax
}
8149 {"pscalib", 0, ActionPSCalib
}
8151 {"ElementList", 0, ActionElementList
,
8152 elementlist_help
, elementlist_syntax
}
8154 {"ElementSetAttr", 0, ActionElementSetAttr
,
8155 elementsetattr_help
, elementsetattr_syntax
}
8157 {"ExecCommand", 0, ActionExecCommand
,
8158 execcommand_help
, execcommand_syntax
}
8160 {"Import", 0, ActionImport
,
8161 import_help
, import_syntax
}
8165 REGISTER_ACTIONS (action_action_list
)