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 */
219 FunctionType
, *FunctionTypePtr
;
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 LayerTypePtr 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 SetZoom (1000); /* special zoom extents */
545 Coord x
= (StrokeBox
.X1
+ StrokeBox
.X2
) / 2;
546 Coord y
= (StrokeBox
.Y1
+ StrokeBox
.Y2
) / 2;
548 /* XXX: PCB->MaxWidth and PCB->MaxHeight may be the wrong
549 * divisors below. The old code WAS broken, but this
550 * replacement has not been tested for correctness.
554 log (fabs (StrokeBox
.X2
- StrokeBox
.X1
) / PCB
->MaxWidth
) /
559 log (fabs (StrokeBox
.Y2
- StrokeBox
.Y1
) / PCB
->MaxHeight
) /
563 CenterDisplay (x
, y
);
568 Message (_("Unknown stroke %s\n"), msg
);
577 /* ---------------------------------------------------------------------------
578 * Clear warning color from pins/pads
583 Settings
.RatWarn
= false;
584 ALLPIN_LOOP (PCB
->Data
);
586 if (TEST_FLAG (WARNFLAG
, pin
))
588 CLEAR_FLAG (WARNFLAG
, pin
);
593 ALLPAD_LOOP (PCB
->Data
);
595 if (TEST_FLAG (WARNFLAG
, pad
))
597 CLEAR_FLAG (WARNFLAG
, pad
);
610 notify_crosshair_change (false);
612 if (Note
.Moving
&& !gui
->shift_is_pressed ())
614 Note
.Buffer
= Settings
.BufferNumber
;
615 SetBufferNumber (MAX_BUFFER
- 1);
616 ClearBuffer (PASTEBUFFER
);
617 AddSelectedToBuffer (PASTEBUFFER
, Note
.X
, Note
.Y
, true);
618 SaveUndoSerialNumber ();
622 SetMode (PASTEBUFFER_MODE
);
624 else if (Note
.Hit
&& !gui
->shift_is_pressed ())
628 SetMode (gui
->control_is_pressed ()? COPY_MODE
: MOVE_MODE
);
629 Crosshair
.AttachedObject
.Ptr1
= Note
.ptr1
;
630 Crosshair
.AttachedObject
.Ptr2
= Note
.ptr2
;
631 Crosshair
.AttachedObject
.Ptr3
= Note
.ptr3
;
632 Crosshair
.AttachedObject
.Type
= Note
.Hit
;
633 AttachForCopy (Note
.X
, Note
.Y
);
641 SaveUndoSerialNumber ();
646 /* unselect first if shift key not down */
647 if (!gui
->shift_is_pressed () && SelectBlock (&box
, false))
648 SetChangedFlag (true);
650 Crosshair
.AttachedBox
.Point1
.X
= Note
.X
;
651 Crosshair
.AttachedBox
.Point1
.Y
= Note
.Y
;
653 notify_crosshair_change (true);
671 Note
.Click
= false; /* inhibit timer action */
672 SaveUndoSerialNumber ();
673 /* unselect first if shift key not down */
674 if (!gui
->shift_is_pressed ())
676 if (SelectBlock (&box
, false))
677 SetChangedFlag (true);
685 RestoreUndoSerialNumber ();
687 SetChangedFlag (true);
691 else if (Note
.Moving
)
693 RestoreUndoSerialNumber ();
695 ClearBuffer (PASTEBUFFER
);
696 SetBufferNumber (Note
.Buffer
);
705 else if (Settings
.Mode
== ARROW_MODE
)
707 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
708 Crosshair
.AttachedBox
.Point2
.X
);
709 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
710 Crosshair
.AttachedBox
.Point2
.Y
);
711 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
712 Crosshair
.AttachedBox
.Point2
.X
);
713 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
714 Crosshair
.AttachedBox
.Point2
.Y
);
715 RestoreUndoSerialNumber ();
716 if (SelectBlock (&box
, true))
717 SetChangedFlag (true);
719 IncrementUndoSerialNumber ();
720 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
727 /* ---------------------------------------------------------------------------
728 * get function ID of passed string
731 static char function_hash
[HSIZE
];
732 static int hash_initted
= 0;
741 i
= (i
* 13) ^ (unsigned char)tolower((int) *s
);
744 i
= (unsigned int)i
% HSIZE
;
749 GetFunctionID (String Ident
)
759 if (HSIZE
< ENTRIES (Functions
) * 2)
761 fprintf(stderr
, _("Error: function hash size too small (%d vs %lu at %s:%d)\n"),
762 HSIZE
, (unsigned long) ENTRIES (Functions
)*2, __FILE__
, __LINE__
);
765 if (ENTRIES (Functions
) > 254)
767 /* Change 'char' to 'int' and remove this when we get to 256
769 fprintf(stderr
, _("Error: function hash type too small (%d vs %lu at %s:%d)\n"),
770 256, (unsigned long) ENTRIES (Functions
), __FILE__
, __LINE__
);
774 for (i
=ENTRIES (Functions
)-1; i
>=0; i
--)
776 h
= hashfunc (Functions
[i
].Identifier
);
777 while (function_hash
[h
])
779 function_hash
[h
] = i
+ 1;
783 i
= hashfunc (Ident
);
786 /* We enforce the "hash table bigger than function table" rule,
787 so we know there will be at least one zero entry to find. */
788 if (!function_hash
[i
])
790 if (!strcasecmp (Ident
, Functions
[function_hash
[i
]-1].Identifier
))
791 return ((int) Functions
[function_hash
[i
]-1].ID
);
796 /* ---------------------------------------------------------------------------
797 * set new coordinates if in 'RECTANGLE' mode
798 * the cursor shape is also adjusted
801 AdjustAttachedBox (void)
803 if (Settings
.Mode
== ARC_MODE
)
805 Crosshair
.AttachedBox
.otherway
= gui
->shift_is_pressed ();
808 switch (Crosshair
.AttachedBox
.State
)
810 case STATE_SECOND
: /* one corner is selected */
812 /* update coordinates */
813 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
814 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
820 /* ---------------------------------------------------------------------------
821 * adjusts the objects which are to be created like attached lines...
824 AdjustAttachedObjects (void)
827 switch (Settings
.Mode
)
829 /* update at least an attached block (selection) */
832 if (Crosshair
.AttachedBox
.State
)
834 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
835 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
839 /* rectangle creation mode */
842 AdjustAttachedBox ();
845 /* polygon creation mode */
847 case POLYGONHOLE_MODE
:
848 AdjustAttachedLine ();
850 /* line creation mode */
852 if (PCB
->RatDraw
|| PCB
->Clipping
== 0)
853 AdjustAttachedLine ();
855 AdjustTwoLine (PCB
->Clipping
- 1);
857 /* point insertion mode */
858 case INSERTPOINT_MODE
:
859 pnt
= AdjustInsertPoint ();
861 InsertedPoint
= *pnt
;
868 /* ---------------------------------------------------------------------------
869 * creates points of a line
875 void *ptr1
, *ptr2
, *ptr3
;
877 if (!Marked
.status
|| TEST_FLAG (LOCALREFFLAG
, PCB
))
878 SetLocalRef (Crosshair
.X
, Crosshair
.Y
, true);
879 switch (Crosshair
.AttachedLine
.State
)
881 case STATE_FIRST
: /* first point */
882 if (PCB
->RatDraw
&& SearchScreen (Crosshair
.X
, Crosshair
.Y
,
883 PAD_TYPE
| PIN_TYPE
, &ptr1
, &ptr1
,
889 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
891 type
= SearchScreen (Crosshair
.X
, Crosshair
.Y
,
892 PIN_TYPE
| PAD_TYPE
| VIA_TYPE
, &ptr1
, &ptr2
,
894 LookupConnection (Crosshair
.X
, Crosshair
.Y
, true, 1,
897 if (type
== PIN_TYPE
|| type
== VIA_TYPE
)
899 Crosshair
.AttachedLine
.Point1
.X
=
900 Crosshair
.AttachedLine
.Point2
.X
= ((PinTypePtr
) ptr2
)->X
;
901 Crosshair
.AttachedLine
.Point1
.Y
=
902 Crosshair
.AttachedLine
.Point2
.Y
= ((PinTypePtr
) ptr2
)->Y
;
904 else if (type
== PAD_TYPE
)
906 PadTypePtr pad
= (PadTypePtr
) ptr2
;
907 double d1
= Distance (Crosshair
.X
, Crosshair
.Y
, pad
->Point1
.X
, pad
->Point1
.Y
);
908 double d2
= Distance (Crosshair
.X
, Crosshair
.Y
, pad
->Point2
.X
, pad
->Point2
.Y
);
911 Crosshair
.AttachedLine
.Point1
=
912 Crosshair
.AttachedLine
.Point2
= pad
->Point2
;
916 Crosshair
.AttachedLine
.Point1
=
917 Crosshair
.AttachedLine
.Point2
= pad
->Point1
;
922 Crosshair
.AttachedLine
.Point1
.X
=
923 Crosshair
.AttachedLine
.Point2
.X
= Crosshair
.X
;
924 Crosshair
.AttachedLine
.Point1
.Y
=
925 Crosshair
.AttachedLine
.Point2
.Y
= Crosshair
.Y
;
927 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
931 /* fall through to third state too */
933 default: /* all following points */
934 Crosshair
.AttachedLine
.State
= STATE_THIRD
;
939 /* ---------------------------------------------------------------------------
940 * create first or second corner of a marked block
945 notify_crosshair_change (false);
946 switch (Crosshair
.AttachedBox
.State
)
948 case STATE_FIRST
: /* setup first point */
949 Crosshair
.AttachedBox
.Point1
.X
=
950 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
951 Crosshair
.AttachedBox
.Point1
.Y
=
952 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
953 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
956 case STATE_SECOND
: /* setup second point */
957 Crosshair
.AttachedBox
.State
= STATE_THIRD
;
960 notify_crosshair_change (true);
964 /* ---------------------------------------------------------------------------
966 * does what's appropriate for the current mode setting. This normally
967 * means creation of an object at the current crosshair location.
969 * new created objects are added to the create undo list of course
974 void *ptr1
, *ptr2
, *ptr3
;
977 if (Settings
.RatWarn
)
979 switch (Settings
.Mode
)
987 /* do something after click time */
988 gui
->add_timer (click_cb
, CLICK_TIME
, hv
);
990 /* see if we clicked on something already selected
991 * (Note.Moving) or clicked on a MOVE_TYPE
994 for (test
= (SELECT_TYPES
| MOVE_TYPES
) & ~RATLINE_TYPE
;
997 type
= SearchScreen (Note
.X
, Note
.Y
, test
, &ptr1
, &ptr2
, &ptr3
);
998 if (!Note
.Hit
&& (type
& MOVE_TYPES
) &&
999 !TEST_FLAG (LOCKFLAG
, (PinTypePtr
) ptr2
))
1006 if (!Note
.Moving
&& (type
& SELECT_TYPES
) &&
1007 TEST_FLAG (SELECTEDFLAG
, (PinTypePtr
) ptr2
))
1009 if ((Note
.Hit
&& Note
.Moving
) || type
== NO_TYPE
)
1021 Message (_("You must turn via visibility on before\n"
1022 "you can place vias\n"));
1025 if ((via
= CreateNewVia (PCB
->Data
, Note
.X
, Note
.Y
,
1026 Settings
.ViaThickness
, 2 * Settings
.Keepaway
,
1027 0, Settings
.ViaDrillingHole
, NULL
,
1028 NoFlags ())) != NULL
)
1030 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1031 if (gui
->shift_is_pressed ())
1032 ChangeObjectThermal (VIA_TYPE
, via
, via
, via
, PCB
->ThermStyle
);
1033 IncrementUndoSerialNumber ();
1042 switch (Crosshair
.AttachedBox
.State
)
1045 Crosshair
.AttachedBox
.Point1
.X
=
1046 Crosshair
.AttachedBox
.Point2
.X
= Note
.X
;
1047 Crosshair
.AttachedBox
.Point1
.Y
=
1048 Crosshair
.AttachedBox
.Point2
.Y
= Note
.Y
;
1049 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
1059 wx
= Note
.X
- Crosshair
.AttachedBox
.Point1
.X
;
1060 wy
= Note
.Y
- Crosshair
.AttachedBox
.Point1
.Y
;
1061 if (XOR (Crosshair
.AttachedBox
.otherway
, abs (wy
) > abs (wx
)))
1063 Crosshair
.AttachedBox
.Point2
.X
=
1064 Crosshair
.AttachedBox
.Point1
.X
+ abs (wy
) * SGNZ (wx
);
1065 sa
= (wx
>= 0) ? 0 : 180;
1067 if (abs (wy
) / 2 >= abs (wx
))
1068 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 45 : -45;
1071 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 90 : -90;
1075 Crosshair
.AttachedBox
.Point2
.Y
=
1076 Crosshair
.AttachedBox
.Point1
.Y
+ abs (wx
) * SGNZ (wy
);
1077 sa
= (wy
>= 0) ? -90 : 90;
1079 if (abs (wx
) / 2 >= abs (wy
))
1080 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -45 : 45;
1083 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -90 : 90;
1086 if (abs (wy
) > 0 && (arc
= CreateNewArcOnLayer (CURRENT
,
1110 bx
= GetArcEnds (arc
);
1111 Crosshair
.AttachedBox
.Point1
.X
=
1112 Crosshair
.AttachedBox
.Point2
.X
= bx
->X2
;
1113 Crosshair
.AttachedBox
.Point1
.Y
=
1114 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y2
;
1115 AddObjectToCreateUndoList (ARC_TYPE
, CURRENT
, arc
, arc
);
1116 IncrementUndoSerialNumber ();
1118 DrawArc (CURRENT
, arc
);
1120 Crosshair
.AttachedBox
.State
= STATE_THIRD
;
1129 type
= SearchScreen (Note
.X
, Note
.Y
, LOCK_TYPES
, &ptr1
, &ptr2
, &ptr3
);
1130 if (type
== ELEMENT_TYPE
)
1132 ElementTypePtr element
= (ElementTypePtr
) ptr2
;
1134 TOGGLE_FLAG (LOCKFLAG
, element
);
1137 TOGGLE_FLAG (LOCKFLAG
, pin
);
1138 CLEAR_FLAG (SELECTEDFLAG
, pin
);
1143 TOGGLE_FLAG (LOCKFLAG
, pad
);
1144 CLEAR_FLAG (SELECTEDFLAG
, pad
);
1147 CLEAR_FLAG (SELECTEDFLAG
, element
);
1148 /* always re-draw it since I'm too lazy
1149 * to tell if a selected flag changed
1151 DrawElement (element
);
1153 hid_actionl ("Report", "Object", NULL
);
1155 else if (type
!= NO_TYPE
)
1157 TextTypePtr thing
= (TextTypePtr
) ptr3
;
1158 TOGGLE_FLAG (LOCKFLAG
, thing
);
1159 if (TEST_FLAG (LOCKFLAG
, thing
)
1160 && TEST_FLAG (SELECTEDFLAG
, thing
))
1162 /* this is not un-doable since LOCK isn't */
1163 CLEAR_FLAG (SELECTEDFLAG
, thing
);
1164 DrawObject (type
, ptr1
, ptr2
);
1167 hid_actionl ("Report", "Object", NULL
);
1175 SearchScreen (Note
.X
, Note
.Y
, PIN_TYPES
, &ptr1
, &ptr2
,
1177 && !TEST_FLAG (HOLEFLAG
, (PinTypePtr
) ptr3
))
1179 if (gui
->shift_is_pressed ())
1181 int tstyle
= GET_THERM (INDEXOFCURRENT
, (PinTypePtr
) ptr3
);
1185 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, tstyle
);
1187 else if (GET_THERM (INDEXOFCURRENT
, (PinTypePtr
) ptr3
))
1188 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, 0);
1190 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, PCB
->ThermStyle
);
1196 /* do update of position */
1198 if (Crosshair
.AttachedLine
.State
!= STATE_THIRD
)
1201 /* Remove anchor if clicking on start point;
1202 * this means we can't paint 0 length lines
1203 * which could be used for square SMD pads.
1204 * Instead use a very small delta, or change
1205 * the file after saving.
1207 if (Crosshair
.X
== Crosshair
.AttachedLine
.Point1
.X
1208 && Crosshair
.Y
== Crosshair
.AttachedLine
.Point1
.Y
)
1210 SetMode (LINE_MODE
);
1217 if ((line
= AddNet ()))
1220 AddObjectToCreateUndoList (RATLINE_TYPE
, line
, line
, line
);
1221 IncrementUndoSerialNumber ();
1223 Crosshair
.AttachedLine
.Point1
.X
=
1224 Crosshair
.AttachedLine
.Point2
.X
;
1225 Crosshair
.AttachedLine
.Point1
.Y
=
1226 Crosshair
.AttachedLine
.Point2
.Y
;
1232 /* create line if both ends are determined && length != 0 */
1235 int maybe_found_flag
;
1238 && Crosshair
.AttachedLine
.Point1
.X
==
1239 Crosshair
.AttachedLine
.Point2
.X
1240 && Crosshair
.AttachedLine
.Point1
.Y
==
1241 Crosshair
.AttachedLine
.Point2
.Y
1242 && (Crosshair
.AttachedLine
.Point2
.X
!= Note
.X
1243 || Crosshair
.AttachedLine
.Point2
.Y
!= Note
.Y
))
1245 /* We will only need to paint the second line segment.
1246 Since we only check for vias on the first segment,
1247 swap them so the non-empty segment is the first segment. */
1248 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1249 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1252 if (TEST_FLAG (AUTODRCFLAG
, PCB
)
1253 && ! TEST_SILK_LAYER (CURRENT
))
1254 maybe_found_flag
= FOUNDFLAG
;
1256 maybe_found_flag
= 0;
1258 if ((Crosshair
.AttachedLine
.Point1
.X
!=
1259 Crosshair
.AttachedLine
.Point2
.X
1260 || Crosshair
.AttachedLine
.Point1
.Y
!=
1261 Crosshair
.AttachedLine
.Point2
.Y
)
1263 CreateDrawnLineOnLayer (CURRENT
,
1264 Crosshair
.AttachedLine
.Point1
.X
,
1265 Crosshair
.AttachedLine
.Point1
.Y
,
1266 Crosshair
.AttachedLine
.Point2
.X
,
1267 Crosshair
.AttachedLine
.Point2
.Y
,
1268 Settings
.LineThickness
,
1269 2 * Settings
.Keepaway
,
1270 MakeFlags (maybe_found_flag
|
1273 PCB
) ? CLEARLINEFLAG
:
1279 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1280 DrawLine (CURRENT
, line
);
1281 /* place a via if vias are visible, the layer is
1282 in a new group since the last line and there
1283 isn't a pin already here */
1284 if (PCB
->ViaOn
&& GetLayerGroupNumberByPointer (CURRENT
) !=
1285 GetLayerGroupNumberByPointer (lastLayer
) &&
1286 SearchObjectByLocation (PIN_TYPES
, &ptr1
, &ptr2
, &ptr3
,
1287 Crosshair
.AttachedLine
.Point1
.X
,
1288 Crosshair
.AttachedLine
.Point1
.Y
,
1289 Settings
.ViaThickness
/ 2) ==
1292 CreateNewVia (PCB
->Data
,
1293 Crosshair
.AttachedLine
.Point1
.X
,
1294 Crosshair
.AttachedLine
.Point1
.Y
,
1295 Settings
.ViaThickness
,
1296 2 * Settings
.Keepaway
, 0,
1297 Settings
.ViaDrillingHole
, NULL
,
1298 NoFlags ())) != NULL
)
1300 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1303 /* copy the coordinates */
1304 Crosshair
.AttachedLine
.Point1
.X
=
1305 Crosshair
.AttachedLine
.Point2
.X
;
1306 Crosshair
.AttachedLine
.Point1
.Y
=
1307 Crosshair
.AttachedLine
.Point2
.Y
;
1308 IncrementUndoSerialNumber ();
1309 lastLayer
= CURRENT
;
1311 if (PCB
->Clipping
&& (Note
.X
!= Crosshair
.AttachedLine
.Point2
.X
1313 Crosshair
.AttachedLine
.Point2
.Y
)
1315 CreateDrawnLineOnLayer (CURRENT
,
1316 Crosshair
.AttachedLine
.Point2
.X
,
1317 Crosshair
.AttachedLine
.Point2
.Y
,
1319 Settings
.LineThickness
,
1320 2 * Settings
.Keepaway
,
1321 MakeFlags ((TEST_FLAG
1323 PCB
) ? FOUNDFLAG
: 0) |
1326 PCB
) ? CLEARLINEFLAG
:
1330 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1331 IncrementUndoSerialNumber ();
1332 DrawLine (CURRENT
, line
);
1333 /* move to new start point */
1334 Crosshair
.AttachedLine
.Point1
.X
= Note
.X
;
1335 Crosshair
.AttachedLine
.Point1
.Y
= Note
.Y
;
1336 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1337 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1338 if (TEST_FLAG (SWAPSTARTDIRFLAG
, PCB
))
1347 case RECTANGLE_MODE
:
1348 /* do update of position */
1351 /* create rectangle if both corners are determined
1352 * and width, height are != 0
1354 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
1355 Crosshair
.AttachedBox
.Point1
.X
!= Crosshair
.AttachedBox
.Point2
.X
&&
1356 Crosshair
.AttachedBox
.Point1
.Y
!= Crosshair
.AttachedBox
.Point2
.Y
)
1358 PolygonTypePtr polygon
;
1360 int flags
= CLEARPOLYFLAG
;
1361 if (TEST_FLAG (NEWFULLPOLYFLAG
, PCB
))
1362 flags
|= FULLPOLYFLAG
;
1363 if ((polygon
= CreateNewPolygonFromRectangle (CURRENT
,
1365 AttachedBox
.Point1
.X
,
1367 AttachedBox
.Point1
.Y
,
1369 AttachedBox
.Point2
.X
,
1371 AttachedBox
.Point2
.Y
,
1376 AddObjectToCreateUndoList (POLYGON_TYPE
, CURRENT
,
1378 IncrementUndoSerialNumber ();
1379 DrawPolygon (CURRENT
, polygon
);
1383 /* reset state to 'first corner' */
1384 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
1392 if ((string
= gui
->prompt_for (_("Enter text:"), "")) != NULL
)
1394 if (strlen(string
) > 0)
1397 int flag
= CLEARLINEFLAG
;
1399 if (GetLayerGroupNumberByNumber (INDEXOFCURRENT
) ==
1400 GetLayerGroupNumberByNumber (solder_silk_layer
))
1401 flag
|= ONSOLDERFLAG
;
1402 if ((text
= CreateNewText (CURRENT
, &PCB
->Font
, Note
.X
,
1403 Note
.Y
, 0, Settings
.TextScale
,
1404 string
, MakeFlags (flag
))) != NULL
)
1406 AddObjectToCreateUndoList (TEXT_TYPE
, CURRENT
, text
, text
);
1407 IncrementUndoSerialNumber ();
1408 DrawText (CURRENT
, text
);
1419 PointTypePtr points
= Crosshair
.AttachedPolygon
.Points
;
1420 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1422 /* do update of position; use the 'LINE_MODE' mechanism */
1425 /* check if this is the last point of a polygon */
1427 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1428 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1430 CopyAttachedPolygonToLayer ();
1435 /* create new point if it's the first one or if it's
1436 * different to the last one
1439 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1440 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1442 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1443 Crosshair
.AttachedLine
.Point2
.X
,
1444 Crosshair
.AttachedLine
.Point2
.Y
);
1446 /* copy the coordinates */
1447 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1448 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1453 case POLYGONHOLE_MODE
:
1455 switch (Crosshair
.AttachedObject
.State
)
1457 /* first notify, lookup object */
1459 Crosshair
.AttachedObject
.Type
=
1460 SearchScreen (Note
.X
, Note
.Y
, POLYGON_TYPE
,
1461 &Crosshair
.AttachedObject
.Ptr1
,
1462 &Crosshair
.AttachedObject
.Ptr2
,
1463 &Crosshair
.AttachedObject
.Ptr3
);
1465 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1467 if (TEST_FLAG (LOCKFLAG
, (PolygonTypePtr
)
1468 Crosshair
.AttachedObject
.Ptr2
))
1470 Message (_("Sorry, the object is locked\n"));
1471 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1475 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1479 /* second notify, insert new point into object */
1482 PointTypePtr points
= Crosshair
.AttachedPolygon
.Points
;
1483 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1484 POLYAREA
*original
, *new_hole
, *result
;
1487 /* do update of position; use the 'LINE_MODE' mechanism */
1490 /* check if this is the last point of a polygon */
1492 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1493 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1495 /* Create POLYAREAs from the original polygon
1496 * and the new hole polygon */
1497 original
= PolygonToPoly ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
);
1498 new_hole
= PolygonToPoly (&Crosshair
.AttachedPolygon
);
1500 /* Subtract the hole from the original polygon shape */
1501 poly_Boolean_free (original
, new_hole
, &result
, PBO_SUB
);
1503 /* Convert the resulting polygon(s) into a new set of nodes
1504 * and place them on the page. Delete the original polygon.
1506 SaveUndoSerialNumber ();
1507 Flags
= ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
)->Flags
;
1508 PolyToPolygonsOnLayer (PCB
->Data
, (LayerType
*)Crosshair
.AttachedObject
.Ptr1
,
1510 RemoveObject (POLYGON_TYPE
,
1511 Crosshair
.AttachedObject
.Ptr1
,
1512 Crosshair
.AttachedObject
.Ptr2
,
1513 Crosshair
.AttachedObject
.Ptr3
);
1514 RestoreUndoSerialNumber ();
1515 IncrementUndoSerialNumber ();
1518 /* reset state of attached line */
1519 memset (&Crosshair
.AttachedPolygon
, 0, sizeof (PolygonType
));
1520 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
1526 /* create new point if it's the first one or if it's
1527 * different to the last one
1530 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1531 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1533 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1534 Crosshair
.AttachedLine
.Point2
.X
,
1535 Crosshair
.AttachedLine
.Point2
.Y
);
1537 /* copy the coordinates */
1538 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1539 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1548 case PASTEBUFFER_MODE
:
1550 TextType estr
[MAX_ELEMENTNAMES
];
1551 ElementTypePtr e
= 0;
1553 if (gui
->shift_is_pressed ())
1556 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1558 if (type
== ELEMENT_TYPE
)
1560 e
= (ElementTypePtr
) ptr1
;
1565 memcpy (estr
, e
->Name
,
1566 MAX_ELEMENTNAMES
* sizeof (TextType
));
1567 for (i
= 0; i
< MAX_ELEMENTNAMES
; ++i
)
1568 estr
[i
].TextString
= estr
[i
].TextString
? strdup(estr
[i
].TextString
) : NULL
;
1573 if (CopyPastebufferToLayout (Note
.X
, Note
.Y
))
1574 SetChangedFlag (true);
1578 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1580 if (type
== ELEMENT_TYPE
&& ptr1
)
1583 e
= (ElementTypePtr
) ptr1
;
1585 save_n
= NAME_INDEX (PCB
);
1587 for (i
= 0; i
< MAX_ELEMENTNAMES
; i
++)
1590 EraseElementName (e
);
1591 r_delete_entry (PCB
->Data
->name_tree
[i
],
1592 (BoxType
*) & (e
->Name
[i
]));
1593 memcpy (&(e
->Name
[i
]), &(estr
[i
]), sizeof (TextType
));
1594 e
->Name
[i
].Element
= e
;
1595 SetTextBoundingBox (&PCB
->Font
, &(e
->Name
[i
]));
1596 r_insert_entry (PCB
->Data
->name_tree
[i
],
1597 (BoxType
*) & (e
->Name
[i
]), 0);
1599 DrawElementName (e
);
1608 SearchScreen (Note
.X
, Note
.Y
, REMOVE_TYPES
, &ptr1
, &ptr2
,
1611 if (TEST_FLAG (LOCKFLAG
, (LineTypePtr
) ptr2
))
1613 Message (_("Sorry, the object is locked\n"));
1616 if (type
== ELEMENT_TYPE
)
1618 RubberbandTypePtr ptr
;
1621 Crosshair
.AttachedObject
.RubberbandN
= 0;
1622 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
1623 ptr
= Crosshair
.AttachedObject
.Rubberband
;
1624 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
; i
++)
1627 EraseRat ((RatTypePtr
) ptr
->Line
);
1628 if (TEST_FLAG (RUBBERENDFLAG
, ptr
->Line
))
1629 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
1630 ptr
->Line
, ptr
->Line
,
1633 TOGGLE_FLAG (RUBBERENDFLAG
, ptr
->Line
); /* only remove line once */
1637 RemoveObject (type
, ptr1
, ptr2
, ptr3
);
1638 IncrementUndoSerialNumber ();
1639 SetChangedFlag (true);
1644 RotateScreenObject (Note
.X
, Note
.Y
,
1645 gui
->shift_is_pressed ()? (SWAP_IDENT
?
1647 : (SWAP_IDENT
? 3 : 1));
1650 /* both are almost the same */
1653 switch (Crosshair
.AttachedObject
.State
)
1655 /* first notify, lookup object */
1658 int types
= (Settings
.Mode
== COPY_MODE
) ?
1659 COPY_TYPES
: MOVE_TYPES
;
1661 Crosshair
.AttachedObject
.Type
=
1662 SearchScreen (Note
.X
, Note
.Y
, types
,
1663 &Crosshair
.AttachedObject
.Ptr1
,
1664 &Crosshair
.AttachedObject
.Ptr2
,
1665 &Crosshair
.AttachedObject
.Ptr3
);
1666 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1668 if (Settings
.Mode
== MOVE_MODE
&&
1669 TEST_FLAG (LOCKFLAG
, (PinTypePtr
)
1670 Crosshair
.AttachedObject
.Ptr2
))
1672 Message (_("Sorry, the object is locked\n"));
1673 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1676 AttachForCopy (Note
.X
, Note
.Y
);
1681 /* second notify, move or copy object */
1683 if (Settings
.Mode
== COPY_MODE
)
1684 CopyObject (Crosshair
.AttachedObject
.Type
,
1685 Crosshair
.AttachedObject
.Ptr1
,
1686 Crosshair
.AttachedObject
.Ptr2
,
1687 Crosshair
.AttachedObject
.Ptr3
,
1688 Note
.X
- Crosshair
.AttachedObject
.X
,
1689 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1692 MoveObjectAndRubberband (Crosshair
.AttachedObject
.Type
,
1693 Crosshair
.AttachedObject
.Ptr1
,
1694 Crosshair
.AttachedObject
.Ptr2
,
1695 Crosshair
.AttachedObject
.Ptr3
,
1696 Note
.X
- Crosshair
.AttachedObject
.X
,
1697 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1698 SetLocalRef (0, 0, false);
1700 SetChangedFlag (true);
1702 /* reset identifiers */
1703 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1704 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1709 /* insert a point into a polygon/line/... */
1710 case INSERTPOINT_MODE
:
1711 switch (Crosshair
.AttachedObject
.State
)
1713 /* first notify, lookup object */
1715 Crosshair
.AttachedObject
.Type
=
1716 SearchScreen (Note
.X
, Note
.Y
, INSERT_TYPES
,
1717 &Crosshair
.AttachedObject
.Ptr1
,
1718 &Crosshair
.AttachedObject
.Ptr2
,
1719 &Crosshair
.AttachedObject
.Ptr3
);
1721 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1723 if (TEST_FLAG (LOCKFLAG
, (PolygonTypePtr
)
1724 Crosshair
.AttachedObject
.Ptr2
))
1726 Message (_("Sorry, the object is locked\n"));
1727 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1732 /* get starting point of nearest segment */
1733 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1736 (PolygonTypePtr
) Crosshair
.AttachedObject
.Ptr2
;
1738 GetLowestDistancePolygonPoint (fake
.poly
, Note
.X
,
1740 fake
.line
.Point1
= fake
.poly
->Points
[polyIndex
];
1741 fake
.line
.Point2
= fake
.poly
->Points
[
1742 prev_contour_point (fake
.poly
, polyIndex
)];
1743 Crosshair
.AttachedObject
.Ptr2
= &fake
.line
;
1746 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1747 InsertedPoint
= *AdjustInsertPoint ();
1752 /* second notify, insert new point into object */
1754 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1755 InsertPointIntoObject (POLYGON_TYPE
,
1756 Crosshair
.AttachedObject
.Ptr1
, fake
.poly
,
1758 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1760 InsertPointIntoObject (Crosshair
.AttachedObject
.Type
,
1761 Crosshair
.AttachedObject
.Ptr1
,
1762 Crosshair
.AttachedObject
.Ptr2
,
1764 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1765 SetChangedFlag (true);
1767 /* reset identifiers */
1768 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1769 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1777 /* --------------------------------------------------------------------------- */
1779 static const char atomic_syntax
[] = "Atomic(Save|Restore|Close|Block)";
1781 static const char atomic_help
[] = "Save or restore the undo serial number.";
1783 /* %start-doc actions Atomic
1785 This action allows making multiple-action bindings into an atomic
1786 operation that will be undone by a single Undo command. For example,
1787 to optimize rat lines, you'd delete the rats and re-add them. To
1788 group these into a single undo, you'd want the deletions and the
1789 additions to have the same undo serial number. So, you @code{Save},
1790 delete the rats, @code{Restore}, add the rats - using the same serial
1791 number as the deletes, then @code{Block}, which checks to see if the
1792 deletions or additions actually did anything. If not, the serial
1793 number is set to the saved number, as there's nothing to undo. If
1794 something did happen, the serial number is incremented so that these
1795 actions are counted as a single undo step.
1800 Saves the undo serial number.
1803 Returns it to the last saved number.
1806 Sets it to 1 greater than the last save.
1809 Does a Restore if there was nothing to undo, else does a Close.
1816 ActionAtomic (int argc
, char **argv
, Coord x
, Coord y
)
1821 switch (GetFunctionID (argv
[0]))
1824 SaveUndoSerialNumber ();
1827 RestoreUndoSerialNumber ();
1830 RestoreUndoSerialNumber ();
1831 IncrementUndoSerialNumber ();
1834 RestoreUndoSerialNumber ();
1836 IncrementUndoSerialNumber ();
1842 /* -------------------------------------------------------------------------- */
1844 static const char drc_syntax
[] = "DRC()";
1846 static const char drc_help
[] = "Invoke the DRC check.";
1848 /* %start-doc actions DRC
1850 Note that the design rule check uses the current board rule settings,
1851 not the current style settings.
1856 ActionDRCheck (int argc
, char **argv
, Coord x
, Coord y
)
1860 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1862 Message (_("%m+Rules are minspace %$mS, minoverlap %$mS "
1863 "minwidth %$mS, minsilk %$mS\n"
1864 "min drill %$mS, min annular ring %$mS\n"),
1865 Settings
.grid_unit
->allow
,
1866 PCB
->Bloat
, PCB
->Shrink
,
1867 PCB
->minWid
, PCB
->minSlk
,
1868 PCB
->minDrill
, PCB
->minRing
);
1871 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1874 Message (_("No DRC problems found.\n"));
1876 Message (_("Found %d design rule errors.\n"), count
);
1878 Message (_("Aborted DRC after %d design rule errors.\n"), -count
);
1883 /* -------------------------------------------------------------------------- */
1885 static const char dumplibrary_syntax
[] = "DumpLibrary()";
1887 static const char dumplibrary_help
[] =
1888 "Display the entire contents of the libraries.";
1890 /* %start-doc actions DumpLibrary
1896 ActionDumpLibrary (int argc
, char **argv
, Coord x
, Coord y
)
1900 printf ("**** Do not count on this format. It will change ****\n\n");
1901 printf ("MenuN = %d\n", Library
.MenuN
);
1902 printf ("MenuMax = %d\n", Library
.MenuMax
);
1903 for (i
= 0; i
< Library
.MenuN
; i
++)
1905 printf ("Library #%d:\n", i
);
1906 printf (" EntryN = %d\n", Library
.Menu
[i
].EntryN
);
1907 printf (" EntryMax = %d\n", Library
.Menu
[i
].EntryMax
);
1908 printf (" Name = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Name
));
1909 printf (" directory = \"%s\"\n",
1910 UNKNOWN (Library
.Menu
[i
].directory
));
1911 printf (" Style = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Style
));
1912 printf (" flag = %d\n", Library
.Menu
[i
].flag
);
1914 for (j
= 0; j
< Library
.Menu
[i
].EntryN
; j
++)
1916 printf (" #%4d: ", j
);
1917 if (Library
.Menu
[i
].Entry
[j
].Template
== (char *) -1)
1919 printf ("newlib: \"%s\"\n",
1920 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
));
1924 printf ("\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"\n",
1925 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
),
1926 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Template
),
1927 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Package
),
1928 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Value
),
1929 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Description
));
1937 /* -------------------------------------------------------------------------- */
1939 static const char flip_syntax
[] = "Flip(Object|Selected|SelectedElements)";
1941 static const char flip_help
[] =
1942 "Flip an element to the opposite side of the board.";
1944 /* %start-doc actions Flip
1946 Note that the location of the element will be symmetric about the
1947 cursor location; i.e. if the part you are pointing at will still be at
1948 the same spot once the element is on the other side. When flipping
1949 multiple elements, this retains their positions relative to each
1950 other, not their absolute positions on the board.
1955 ActionFlip (int argc
, char **argv
, Coord x
, Coord y
)
1957 char *function
= ARG (0);
1958 ElementTypePtr element
;
1964 switch (GetFunctionID (function
))
1967 if ((SearchScreen (x
, y
, ELEMENT_TYPE
,
1968 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
1970 element
= (ElementTypePtr
) ptrtmp
;
1971 ChangeElementSide (element
, 2 * Crosshair
.Y
- PCB
->MaxHeight
);
1972 IncrementUndoSerialNumber ();
1977 case F_SelectedElements
:
1978 ChangeSelectedElementSide ();
1991 /* -------------------------------------------------------------------------- */
1993 static const char message_syntax
[] = "Message(message)";
1995 static const char message_help
[] = "Writes a message to the log window.";
1997 /* %start-doc actions Message
1999 This action displays a message to the log window. This action is primarily
2000 provided for use by other programs which may interface with PCB. If
2001 multiple arguments are given, each one is sent to the log window
2002 followed by a newline.
2007 ActionMessage (int argc
, char **argv
, Coord x
, Coord y
)
2014 for (i
= 0; i
< argc
; i
++)
2024 /* -------------------------------------------------------------------------- */
2026 static const char setthermal_syntax
[] =
2027 "SetThermal(Object|SelectedPins|SelectedVias|Selected, Style)";
2029 static const char setthermal_help
[] =
2030 "Set the thermal (on the current layer) of pins or vias to the given style.\n"
2031 "Style = 0 means no thermal.\n"
2032 "Style = 1 has diagonal fingers with sharp edges.\n"
2033 "Style = 2 has horizontal and vertical fingers with sharp edges.\n"
2034 "Style = 3 is a solid connection to the plane."
2035 "Style = 4 has diagonal fingers with rounded edges.\n"
2036 "Style = 5 has horizontal and vertical fingers with rounded edges.\n";
2038 /* %start-doc actions SetThermal
2040 This changes how/whether pins or vias connect to any rectangle or polygon
2041 on the current layer. The first argument can specify one object, or all
2042 selected pins, or all selected vias, or all selected pins and vias.
2043 The second argument specifies the style of connection.
2044 There are 5 possibilities:
2046 1 - 45 degree fingers with sharp edges,
2047 2 - horizontal & vertical fingers with sharp edges,
2048 3 - solid connection,
2049 4 - 45 degree fingers with rounded corners,
2050 5 - horizontal & vertical fingers with rounded corners.
2052 Pins and Vias may have thermals whether or not there is a polygon available
2053 to connect with. However, they will have no effect without the polygon.
2057 ActionSetThermal (int argc
, char **argv
, Coord x
, Coord y
)
2059 char *function
= ARG (0);
2060 char *style
= ARG (1);
2061 void *ptr1
, *ptr2
, *ptr3
;
2065 if (function
&& *function
&& style
&& *style
)
2069 kind
= GetValue (style
, NULL
, &absolute
);
2071 switch (GetFunctionID (function
))
2075 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGETHERMAL_TYPES
,
2076 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
2078 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, kind
);
2079 IncrementUndoSerialNumber ();
2083 case F_SelectedPins
:
2084 ChangeSelectedThermals (PIN_TYPE
, kind
);
2086 case F_SelectedVias
:
2087 ChangeSelectedThermals (VIA_TYPE
, kind
);
2090 case F_SelectedElements
:
2091 ChangeSelectedThermals (CHANGETHERMAL_TYPES
, kind
);
2106 /* ---------------------------------------------------------------------------
2107 * !!! no action routine !!!
2109 * event handler to set the cursor according to the X pointer position
2110 * called from inside main.c
2113 EventMoveCrosshair (int ev_x
, int ev_y
)
2115 #ifdef HAVE_LIBSTROKE
2118 StrokeBox
.X2
= ev_x
;
2119 StrokeBox
.Y2
= ev_y
;
2120 stroke_record (ev_x
, ev_y
);
2123 #endif /* HAVE_LIBSTROKE */
2124 if (MoveCrosshairAbsolute (ev_x
, ev_y
))
2126 /* update object position and cursor location */
2127 AdjustAttachedObjects ();
2128 notify_crosshair_change (true);
2132 /* --------------------------------------------------------------------------- */
2134 static const char setvalue_syntax
[] =
2135 "SetValue(Grid|Line|LineSize|Text|TextScale|ViaDrillingHole|Via|ViaSize, delta)";
2137 static const char setvalue_help
[] =
2138 "Change various board-wide values and sizes.";
2140 /* %start-doc actions SetValue
2144 @item ViaDrillingHole
2145 Changes the diameter of the drill for new vias.
2148 Sets the grid spacing.
2152 Changes the thickness of new lines.
2156 Changes the diameter of new vias.
2160 Changes the size of new text.
2167 ActionSetValue (int argc
, char **argv
, Coord x
, Coord y
)
2169 char *function
= ARG (0);
2170 char *val
= ARG (1);
2171 char *units
= ARG (2);
2172 bool absolute
; /* flag for 'absolute' value */
2177 if (function
&& val
)
2179 value
= GetValue (val
, units
, &absolute
);
2180 switch (GetFunctionID (function
))
2182 case F_ViaDrillingHole
:
2183 SetViaDrillingHole (absolute
? value
:
2184 value
+ Settings
.ViaDrillingHole
,
2186 hid_action ("RouteStylesChanged");
2191 SetGrid (value
, false);
2194 /* On the way down, short against the minimum
2195 * PCB drawing unit */
2196 if ((value
+ PCB
->Grid
) < 1)
2198 else if (PCB
->Grid
== 1)
2199 SetGrid (value
, false);
2201 SetGrid (value
+ PCB
->Grid
, false);
2207 SetLineSize (absolute
? value
: value
+ Settings
.LineThickness
);
2208 hid_action ("RouteStylesChanged");
2213 SetViaSize (absolute
? value
: value
+ Settings
.ViaThickness
, false);
2214 hid_action ("RouteStylesChanged");
2219 text_scale
= value
/ (double)FONT_CAPHEIGHT
* 100.;
2221 text_scale
+= Settings
.TextScale
;
2222 SetTextScale (text_scale
);
2236 /* --------------------------------------------------------------------------- */
2238 static const char quit_syntax
[] = "Quit()";
2240 static const char quit_help
[] = "Quits the application after confirming.";
2242 /* %start-doc actions Quit
2244 If you have unsaved changes, you will be prompted to confirm (or
2245 save) before quitting.
2250 ActionQuit (int argc
, char **argv
, Coord x
, Coord y
)
2252 char *force
= ARG (0);
2253 if (force
&& strcasecmp (force
, "force") == 0)
2258 if (!PCB
->Changed
|| gui
->close_confirm_dialog () == HID_CLOSE_CONFIRM_OK
)
2263 /* --------------------------------------------------------------------------- */
2265 static const char connection_syntax
[] =
2266 "Connection(Find|ResetLinesAndPolygons|ResetPinsAndVias|Reset)";
2268 static const char connection_help
[] =
2269 "Searches connections of the object at the cursor position.";
2271 /* %start-doc actions Connection
2273 Connections found with this action will be highlighted in the
2274 ``connected-color'' color and will have the ``found'' flag set.
2279 The net under the cursor is ``found''.
2281 @item ResetLinesAndPolygons
2282 Any ``found'' lines and polygons are marked ``not found''.
2284 @item ResetPinsAndVias
2285 Any ``found'' pins and vias are marked ``not found''.
2288 All ``found'' objects are marked ``not found''.
2295 ActionConnection (int argc
, char **argv
, Coord x
, Coord y
)
2297 char *function
= ARG (0);
2300 switch (GetFunctionID (function
))
2304 gui
->get_coords (_("Click on a connection"), &x
, &y
);
2305 LookupConnection (x
, y
, true, 1, FOUNDFLAG
);
2309 case F_ResetLinesAndPolygons
:
2310 if (ResetFoundLinesAndPolygons (true))
2312 IncrementUndoSerialNumber ();
2317 case F_ResetPinsViasAndPads
:
2318 if (ResetFoundPinsViasAndPads (true))
2320 IncrementUndoSerialNumber ();
2326 if (ResetConnections (true))
2328 IncrementUndoSerialNumber ();
2339 /* --------------------------------------------------------------------------- */
2341 static const char disperseelements_syntax
[] =
2342 "DisperseElements(All|Selected)";
2344 static const char disperseelements_help
[] = "Disperses elements.";
2346 /* %start-doc actions DisperseElements
2348 Normally this is used when starting a board, by selecting all elements
2349 and then dispersing them. This scatters the elements around the board
2350 so that you can pick individual ones, rather than have all the
2351 elements at the same 0,0 coordinate and thus impossible to choose
2356 #define GAP MIL_TO_COORD(100)
2359 ActionDisperseElements (int argc
, char **argv
, Coord x
, Coord y
)
2361 char *function
= ARG (0);
2366 int all
= 0, bad
= 0;
2368 if (!function
|| !*function
)
2374 switch (GetFunctionID (function
))
2391 AFAIL (disperseelements
);
2395 ELEMENT_LOOP (PCB
->Data
);
2398 * If we want to disperse selected elements, maybe we need smarter
2399 * code here to avoid putting components on top of others which
2400 * are not selected. For now, I'm assuming that this is typically
2401 * going to be used either with a brand new design or a scratch
2402 * design holding some new components
2404 if (!TEST_FLAG (LOCKFLAG
, element
) && (all
|| TEST_FLAG (SELECTEDFLAG
, element
)))
2407 /* figure out how much to move the element */
2408 dx
= minx
- element
->BoundingBox
.X1
;
2410 /* snap to the grid */
2411 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2414 * and add one grid size so we make sure we always space by GAP or
2419 /* Figure out if this row has room. If not, start a new row */
2420 if (GAP
+ element
->BoundingBox
.X2
+ dx
> PCB
->MaxWidth
)
2426 /* figure out how much to move the element */
2427 dx
= minx
- element
->BoundingBox
.X1
;
2428 dy
= miny
- element
->BoundingBox
.Y1
;
2430 /* snap to the grid */
2431 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2433 dy
-= (element
->MarkY
+ dy
) % PCB
->Grid
;
2436 /* move the element */
2437 MoveElementLowLevel (PCB
->Data
, element
, dx
, dy
);
2439 /* and add to the undo list so we can undo this operation */
2440 AddObjectToMoveUndoList (ELEMENT_TYPE
, NULL
, NULL
, element
, dx
, dy
);
2442 /* keep track of how tall this row is */
2443 minx
+= element
->BoundingBox
.X2
- element
->BoundingBox
.X1
+ GAP
;
2444 if (maxy
< element
->BoundingBox
.Y2
)
2446 maxy
= element
->BoundingBox
.Y2
;
2453 /* done with our action so increment the undo # */
2454 IncrementUndoSerialNumber ();
2457 SetChangedFlag (true);
2464 /* --------------------------------------------------------------------------- */
2466 static const char display_syntax
[] =
2467 "Display(NameOnPCB|Description|Value)\n"
2468 "Display(Grid|Redraw)\n"
2469 "Display(CycleClip|CycleCrosshair|Toggle45Degree|ToggleStartDirection)\n"
2470 "Display(ToggleGrid|ToggleRubberBandMode|ToggleUniqueNames)\n"
2471 "Display(ToggleMask|ToggleName|ToggleClearLine|ToggleFullPoly|ToggleSnapPin)\n"
2472 "Display(ToggleThindraw|ToggleThindrawPoly|ToggleOrthoMove|ToggleLocalRef)\n"
2473 "Display(ToggleCheckPlanes|ToggleShowDRC|ToggleAutoDRC)\n"
2474 "Display(ToggleLiveRoute|LockNames|OnlyNames)\n"
2475 "Display(Pinout|PinOrPadName)";
2477 static const char display_help
[] = "Several display-related actions.";
2479 /* %start-doc actions Display
2486 Specify whether all elements show their name, description, or value.
2489 Redraw the whole board.
2491 @item Toggle45Degree
2492 When clear, lines can be drawn at any angle. When set, lines are
2493 restricted to multiples of 45 degrees and requested lines may be
2494 broken up according to the clip setting.
2497 Changes the way lines are restricted to 45 degree increments. The
2498 various settings are: straight only, orthogonal then angled, and angled
2499 then orthogonal. If AllDirections is set, this action disables it.
2501 @item CycleCrosshair
2502 Changes crosshair drawing. Crosshair may accept form of 4-ray,
2503 8-ray and 12-ray cross.
2505 @item ToggleRubberBandMode
2506 If set, moving an object moves all the lines attached to it too.
2508 @item ToggleStartDirection
2509 If set, each time you set a point in a line, the Clip toggles between
2510 orth-angle and angle-ortho.
2512 @item ToggleUniqueNames
2513 If set, you will not be permitted to change the name of an element to
2514 match that of another element.
2517 If set, pin centers and pad end points are treated as additional grid
2518 points that the cursor can snap to.
2520 @item ToggleLocalRef
2521 If set, the mark is automatically set to the beginning of any move, so
2522 you can see the relative distance you've moved.
2524 @item ToggleThindraw
2525 If set, objects on the screen are drawn as outlines (lines are drawn
2526 as center-lines). This lets you see line endpoints hidden under pins,
2529 @item ToggleThindrawPoly
2530 If set, polygons on the screen are drawn as outlines.
2533 If set, pending objects (i.e. lines you're in the process of drawing)
2534 will be drawn with an outline showing how far away from other copper
2537 @item ToggleLiveRoute
2538 If set, the progress of the autorouter will be visible on the screen.
2541 If set, you will not be permitted to make connections which violate
2542 the current DRC and netlist settings.
2544 @item ToggleCheckPlanes
2545 If set, lines and arcs aren't drawn, which usually leaves just the
2546 polygons. If you also disable all but the layer you're interested in,
2547 this allows you to check for isolated regions.
2549 @item ToggleOrthoMove
2550 If set, the crosshair is only allowed to move orthogonally from its
2551 previous position. I.e. you can move an element or line up, down,
2552 left, or right, but not up+left or down+right.
2555 Selects whether the pinouts show the pin names or the pin numbers.
2557 @item ToggleLockNames
2558 If set, text will ignore left mouse clicks and actions that work on
2559 objects under the mouse. You can still select text with a lasso (left
2560 mouse drag) and perform actions on the selection.
2562 @item ToggleOnlyNames
2563 If set, only text will be sensitive for mouse clicks and actions that
2564 work on objects under the mouse. You can still select other objects
2565 with a lasso (left mouse drag) and perform actions on the selection.
2568 Turns the solder mask on or off.
2570 @item ToggleClearLine
2571 When set, the clear-line flag causes new lines and arcs to have their
2572 ``clear polygons'' flag set, so they won't be electrically connected
2573 to any polygons they overlap.
2575 @item ToggleFullPoly
2576 When set, the full-poly flag causes new polygons to have their
2577 ``full polygon'' flag set, so all parts of them will be displayed
2578 instead of only the biggest one.
2581 Resets the origin of the current grid to be wherever the mouse pointer
2582 is (not where the crosshair currently is). If you provide two numbers
2583 after this, the origin is set to that coordinate.
2586 Toggles whether the grid is displayed or not.
2589 Causes the pinout of the element indicated by the cursor to be
2590 displayed, usually in a separate window.
2593 Toggles whether the names of pins, pads, or (yes) vias will be
2594 displayed. If the cursor is over an element, all of its pins and pads
2601 static enum crosshair_shape
2602 CrosshairShapeIncrement (enum crosshair_shape shape
)
2606 case Basic_Crosshair_Shape
:
2607 shape
= Union_Jack_Crosshair_Shape
;
2609 case Union_Jack_Crosshair_Shape
:
2610 shape
= Dozen_Crosshair_Shape
;
2612 case Dozen_Crosshair_Shape
:
2613 shape
= Crosshair_Shapes_Number
;
2615 case Crosshair_Shapes_Number
:
2616 shape
= Basic_Crosshair_Shape
;
2623 ActionDisplay (int argc
, char **argv
, Coord childX
, Coord childY
)
2625 char *function
, *str_dir
;
2632 if (function
&& (!str_dir
|| !*str_dir
))
2634 switch (id
= GetFunctionID (function
))
2638 case F_ClearAndRedraw
:
2643 /* change the displayed name of elements */
2647 ELEMENT_LOOP (PCB
->Data
);
2649 EraseElementName (element
);
2652 CLEAR_FLAG (DESCRIPTIONFLAG
| NAMEONPCBFLAG
, PCB
);
2658 SET_FLAG (NAMEONPCBFLAG
, PCB
);
2661 SET_FLAG (DESCRIPTIONFLAG
, PCB
);
2664 ELEMENT_LOOP (PCB
->Data
);
2666 DrawElementName (element
);
2672 /* toggle line-adjust flag */
2673 case F_ToggleAllDirections
:
2674 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2675 AdjustAttachedObjects ();
2679 notify_crosshair_change (false);
2680 if (TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
2682 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2686 PCB
->Clipping
= (PCB
->Clipping
+ 1) % 3;
2687 AdjustAttachedObjects ();
2688 notify_crosshair_change (true);
2691 case F_CycleCrosshair
:
2692 notify_crosshair_change (false);
2693 Crosshair
.shape
= CrosshairShapeIncrement(Crosshair
.shape
);
2694 if (Crosshair_Shapes_Number
== Crosshair
.shape
)
2695 Crosshair
.shape
= Basic_Crosshair_Shape
;
2696 notify_crosshair_change (true);
2699 case F_ToggleRubberBandMode
:
2700 notify_crosshair_change (false);
2701 TOGGLE_FLAG (RUBBERBANDFLAG
, PCB
);
2702 notify_crosshair_change (true);
2705 case F_ToggleStartDirection
:
2706 notify_crosshair_change (false);
2707 TOGGLE_FLAG (SWAPSTARTDIRFLAG
, PCB
);
2708 notify_crosshair_change (true);
2711 case F_ToggleUniqueNames
:
2712 TOGGLE_FLAG (UNIQUENAMEFLAG
, PCB
);
2715 case F_ToggleSnapPin
:
2716 notify_crosshair_change (false);
2717 TOGGLE_FLAG (SNAPPINFLAG
, PCB
);
2718 notify_crosshair_change (true);
2721 case F_ToggleLocalRef
:
2722 TOGGLE_FLAG (LOCALREFFLAG
, PCB
);
2725 case F_ToggleThindraw
:
2726 TOGGLE_FLAG (THINDRAWFLAG
, PCB
);
2730 case F_ToggleThindrawPoly
:
2731 TOGGLE_FLAG (THINDRAWPOLYFLAG
, PCB
);
2735 case F_ToggleLockNames
:
2736 TOGGLE_FLAG (LOCKNAMESFLAG
, PCB
);
2737 CLEAR_FLAG (ONLYNAMESFLAG
, PCB
);
2740 case F_ToggleOnlyNames
:
2741 TOGGLE_FLAG (ONLYNAMESFLAG
, PCB
);
2742 CLEAR_FLAG (LOCKNAMESFLAG
, PCB
);
2745 case F_ToggleHideNames
:
2746 TOGGLE_FLAG (HIDENAMESFLAG
, PCB
);
2750 case F_ToggleShowDRC
:
2751 TOGGLE_FLAG (SHOWDRCFLAG
, PCB
);
2754 case F_ToggleLiveRoute
:
2755 TOGGLE_FLAG (LIVEROUTEFLAG
, PCB
);
2758 case F_ToggleAutoDRC
:
2759 notify_crosshair_change (false);
2760 TOGGLE_FLAG (AUTODRCFLAG
, PCB
);
2761 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
2763 if (ResetConnections (true))
2765 IncrementUndoSerialNumber ();
2768 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
2769 LookupConnection (Crosshair
.AttachedLine
.Point1
.X
,
2770 Crosshair
.AttachedLine
.Point1
.Y
, true, 1,
2773 notify_crosshair_change (true);
2776 case F_ToggleCheckPlanes
:
2777 TOGGLE_FLAG (CHECKPLANESFLAG
, PCB
);
2781 case F_ToggleOrthoMove
:
2782 TOGGLE_FLAG (ORTHOMOVEFLAG
, PCB
);
2786 TOGGLE_FLAG (SHOWNUMBERFLAG
, PCB
);
2791 TOGGLE_FLAG (SHOWMASKFLAG
, PCB
);
2795 case F_ToggleClearLine
:
2796 TOGGLE_FLAG (CLEARNEWFLAG
, PCB
);
2799 case F_ToggleFullPoly
:
2800 TOGGLE_FLAG (NEWFULLPOLYFLAG
, PCB
);
2803 /* shift grid alignment */
2806 Coord oldGrid
= PCB
->Grid
;
2809 if (MoveCrosshairAbsolute (Crosshair
.X
, Crosshair
.Y
))
2810 notify_crosshair_change (true); /* first notify was in MoveCrosshairAbs */
2811 SetGrid (oldGrid
, true);
2815 /* toggle displaying of the grid */
2817 Settings
.DrawGrid
= !Settings
.DrawGrid
;
2821 /* display the pinout of an element */
2824 ElementTypePtr element
;
2828 gui
->get_coords (_("Click on an element"), &x
, &y
);
2830 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
2831 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
2833 element
= (ElementTypePtr
) ptrtmp
;
2834 gui
->show_item (element
);
2839 /* toggle displaying of pin/pad/via names */
2840 case F_PinOrPadName
:
2842 void *ptr1
, *ptr2
, *ptr3
;
2844 switch (SearchScreen (Crosshair
.X
, Crosshair
.Y
,
2845 ELEMENT_TYPE
| PIN_TYPE
| PAD_TYPE
|
2846 VIA_TYPE
, (void **) &ptr1
, (void **) &ptr2
,
2850 PIN_LOOP ((ElementTypePtr
) ptr1
);
2852 if (TEST_FLAG (DISPLAYNAMEFLAG
, pin
))
2856 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, pin
, pin
);
2857 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pin
);
2860 PAD_LOOP ((ElementTypePtr
) ptr1
);
2862 if (TEST_FLAG (DISPLAYNAMEFLAG
, pad
))
2866 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, pad
, pad
);
2867 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pad
);
2870 SetChangedFlag (true);
2871 IncrementUndoSerialNumber ();
2876 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinTypePtr
) ptr2
))
2877 ErasePinName ((PinTypePtr
) ptr2
);
2879 DrawPinName ((PinTypePtr
) ptr2
);
2880 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, ptr2
, ptr3
);
2881 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinTypePtr
) ptr2
);
2882 SetChangedFlag (true);
2883 IncrementUndoSerialNumber ();
2888 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PadTypePtr
) ptr2
))
2889 ErasePadName ((PadTypePtr
) ptr2
);
2891 DrawPadName ((PadTypePtr
) ptr2
);
2892 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, ptr2
, ptr3
);
2893 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PadTypePtr
) ptr2
);
2894 SetChangedFlag (true);
2895 IncrementUndoSerialNumber ();
2899 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinTypePtr
) ptr2
))
2900 EraseViaName ((PinTypePtr
) ptr2
);
2902 DrawViaName ((PinTypePtr
) ptr2
);
2903 AddObjectToFlagUndoList (VIA_TYPE
, ptr1
, ptr2
, ptr3
);
2904 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinTypePtr
) ptr2
);
2905 SetChangedFlag (true);
2906 IncrementUndoSerialNumber ();
2916 else if (function
&& str_dir
)
2918 switch (GetFunctionID (function
))
2923 PCB
->GridOffsetX
= GetValue (argv
[1], NULL
, NULL
);
2924 PCB
->GridOffsetY
= GetValue (argv
[2], NULL
, NULL
);
2925 if (Settings
.DrawGrid
)
2942 /* --------------------------------------------------------------------------- */
2944 static const char mode_syntax
[] =
2945 "Mode(Arc|Arrow|Copy|InsertPoint|Line|Lock|Move|None|PasteBuffer)\n"
2946 "Mode(Polygon|Rectangle|Remove|Rotate|Text|Thermal|Via)\n"
2947 "Mode(Notify|Release|Cancel|Stroke)\n"
2948 "Mode(Save|Restore)";
2950 static const char mode_help
[] = "Change or use the tool mode.";
2952 /* %start-doc actions Mode
2972 Select the indicated tool.
2975 Called when you press the mouse button, or move the mouse.
2978 Called when you release the mouse button.
2981 Cancels any pending tool activity, allowing you to restart elsewhere.
2982 For example, this allows you to start a new line rather than attach a
2983 line to the previous line.
2986 Similar to Cancel but calling this action a second time will return
2990 If your @code{pcb} was built with libstroke, this invokes the stroke
2991 input method. If not, this will restart a drawing mode if you were
2992 drawing, else it will select objects.
2995 Remembers the current tool.
2998 Restores the tool to the last saved tool.
3005 ActionMode (int argc
, char **argv
, Coord x
, Coord y
)
3007 char *function
= ARG (0);
3011 Note
.X
= Crosshair
.X
;
3012 Note
.Y
= Crosshair
.Y
;
3013 notify_crosshair_change (false);
3014 switch (GetFunctionID (function
))
3020 SetMode (ARROW_MODE
);
3023 SetMode (COPY_MODE
);
3026 SetMode (INSERTPOINT_MODE
);
3029 SetMode (LINE_MODE
);
3032 SetMode (LOCK_MODE
);
3035 SetMode (MOVE_MODE
);
3042 int saved_mode
= Settings
.Mode
;
3044 SetMode (saved_mode
);
3049 switch (Settings
.Mode
)
3052 case PASTEBUFFER_MODE
:
3058 case INSERTPOINT_MODE
:
3059 case RUBBERBANDMOVE_MODE
:
3063 SetMode (ARROW_MODE
);
3067 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3068 SetMode (ARROW_MODE
);
3072 SetMode (LINE_MODE
);
3076 case RECTANGLE_MODE
:
3077 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3078 SetMode (ARROW_MODE
);
3082 SetMode (RECTANGLE_MODE
);
3087 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3088 SetMode (ARROW_MODE
);
3092 SetMode (POLYGON_MODE
);
3096 case POLYGONHOLE_MODE
:
3097 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3098 SetMode (ARROW_MODE
);
3102 SetMode (POLYGONHOLE_MODE
);
3107 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3108 SetMode (ARROW_MODE
);
3129 SetMode (PASTEBUFFER_MODE
);
3132 SetMode (POLYGON_MODE
);
3135 SetMode (POLYGONHOLE_MODE
);
3137 #ifndef HAVE_LIBSTROKE
3150 SetMode (REMOVE_MODE
);
3153 SetMode (RECTANGLE_MODE
);
3156 SetMode (ROTATE_MODE
);
3159 #ifdef HAVE_LIBSTROKE
3161 StrokeBox
.X1
= Crosshair
.X
;
3162 StrokeBox
.Y1
= Crosshair
.Y
;
3165 /* Handle middle mouse button restarts of drawing mode. If not in
3166 | a drawing mode, middle mouse button will select objects.
3168 if (Settings
.Mode
== LINE_MODE
3169 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3171 SetMode (LINE_MODE
);
3173 else if (Settings
.Mode
== ARC_MODE
3174 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3176 else if (Settings
.Mode
== RECTANGLE_MODE
3177 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3178 SetMode (RECTANGLE_MODE
);
3179 else if (Settings
.Mode
== POLYGON_MODE
3180 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3181 SetMode (POLYGON_MODE
);
3186 SetMode (ARROW_MODE
);
3192 SetMode (TEXT_MODE
);
3195 SetMode (THERMAL_MODE
);
3201 case F_Restore
: /* restore the last saved mode */
3205 case F_Save
: /* save currently selected mode */
3209 notify_crosshair_change (true);
3216 /* --------------------------------------------------------------------------- */
3218 static const char removeselected_syntax
[] = "RemoveSelected()";
3220 static const char removeselected_help
[] = "Removes any selected objects.";
3222 /* %start-doc actions RemoveSelected
3227 ActionRemoveSelected (int argc
, char **argv
, Coord x
, Coord y
)
3229 if (RemoveSelected ())
3230 SetChangedFlag (true);
3234 /* --------------------------------------------------------------------------- */
3236 static const char renumber_syntax
[] = "Renumber()\n"
3237 "Renumber(filename)";
3239 static const char renumber_help
[] =
3240 "Renumber all elements. The changes will be recorded to filename\n"
3241 "for use in backannotating these changes to the schematic.";
3243 /* %start-doc actions Renumber
3248 ActionRenumber (int argc
, char **argv
, Coord x
, Coord y
)
3250 bool changed
= false;
3251 ElementTypePtr
*element_list
;
3252 ElementTypePtr
*locked_element_list
;
3253 unsigned int i
, j
, k
, cnt
, lock_cnt
;
3259 static char * default_file
= NULL
;
3260 size_t cnt_list_sz
= 100;
3266 char **was
, **is
, *pin
;
3267 unsigned int c_cnt
= 0;
3274 * We deal with the case where name already exists in this
3275 * function so the GUI doesn't need to deal with it
3277 name
= gui
->fileselect (_("Save Renumber Annotation File As ..."),
3278 _("Choose a file to record the renumbering to.\n"
3279 "This file may be used to back annotate the\n"
3280 "change to the schematics.\n"),
3281 default_file
, ".eco", "eco",
3291 free (default_file
);
3292 default_file
= NULL
;
3297 default_file
= strdup (name
);
3300 if ((out
= fopen (name
, "r")))
3303 if (!gui
->confirm_dialog (_("File exists! Ok to overwrite?"), 0))
3305 if (free_name
&& name
)
3311 if ((out
= fopen (name
, "w")) == NULL
)
3313 Message (_("Could not open %s\n"), name
);
3314 if (free_name
&& name
)
3319 if (free_name
&& name
)
3322 fprintf (out
, "*COMMENT* PCB Annotation File\n");
3323 fprintf (out
, "*FILEVERSION* 20061031\n");
3326 * Make a first pass through all of the elements and sort them out
3327 * by location on the board. While here we also collect a list of
3330 * We'll actually renumber things in the 2nd pass.
3332 element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementTypePtr
));
3333 locked_element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementTypePtr
));
3334 was
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3335 is
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3336 if (element_list
== NULL
|| locked_element_list
== NULL
|| was
== NULL
3339 fprintf (stderr
, "calloc() failed in %s\n", __FUNCTION__
);
3346 ELEMENT_LOOP (PCB
->Data
);
3348 if (TEST_FLAG (LOCKFLAG
, element
->Name
) || TEST_FLAG (LOCKFLAG
, element
))
3351 * add to the list of locked elements which we won't try to
3352 * renumber and whose reference designators are now reserved.
3355 "*WARN* Element \"%s\" at %$md is locked and will not be renumbered.\n",
3356 UNKNOWN (NAMEONPCB_NAME (element
)), element
->MarkX
, element
->MarkY
);
3357 locked_element_list
[lock_cnt
] = element
;
3363 /* count of devices which will be renumbered */
3366 /* search for correct position in the list */
3368 while (element_list
[i
] && element
->MarkY
> element_list
[i
]->MarkY
)
3372 * We have found the position where we have the first element that
3373 * has the same Y value or a lower Y value. Now move forward if
3374 * needed through the X values
3376 while (element_list
[i
]
3377 && element
->MarkY
== element_list
[i
]->MarkY
3378 && element
->MarkX
> element_list
[i
]->MarkX
)
3381 for (j
= cnt
- 1; j
> i
; j
--)
3383 element_list
[j
] = element_list
[j
- 1];
3385 element_list
[i
] = element
;
3392 * Now that the elements are sorted by board position, we go through
3393 * and renumber them.
3397 * turn off the flag which requires unique names so it doesn't get
3398 * in our way. When we're done with the renumber we will have unique
3401 unique
= TEST_FLAG (UNIQUENAMEFLAG
, PCB
);
3402 CLEAR_FLAG (UNIQUENAMEFLAG
, PCB
);
3404 cnt_list
= (struct _cnt_list
*)calloc (cnt_list_sz
, sizeof (struct _cnt_list
));
3405 for (i
= 0; i
< cnt
; i
++)
3407 /* If there is no refdes, maybe just spit out a warning */
3408 if (NAMEONPCB_NAME (element_list
[i
]))
3410 /* figure out the prefix */
3411 tmps
= strdup (NAMEONPCB_NAME (element_list
[i
]));
3413 while (tmps
[j
] && (tmps
[j
] < '0' || tmps
[j
] > '9')
3418 /* check the counter for this prefix */
3420 cnt_list
[j
].name
&& (strcmp (cnt_list
[j
].name
, tmps
) != 0)
3421 && j
< cnt_list_sz
; j
++);
3423 /* grow the list if needed */
3424 if (j
== cnt_list_sz
)
3427 cnt_list
= (struct _cnt_list
*)realloc (cnt_list
, cnt_list_sz
);
3428 if (cnt_list
== NULL
)
3430 fprintf (stderr
, "realloc failed() in %s\n", __FUNCTION__
);
3433 /* zero out the memory that we added */
3434 for (tmpi
= j
; tmpi
< cnt_list_sz
; tmpi
++)
3436 cnt_list
[tmpi
].name
= NULL
;
3437 cnt_list
[tmpi
].cnt
= 0;
3442 * start a new counter if we don't have a counter for this
3445 if (!cnt_list
[j
].name
)
3447 cnt_list
[j
].name
= strdup (tmps
);
3448 cnt_list
[j
].cnt
= 0;
3452 * check to see if the new refdes is already used by a
3461 /* space for the prefix plus 1 digit plus the '\0' */
3462 sz
= strlen (cnt_list
[j
].name
) + 2;
3464 /* and 1 more per extra digit needed to hold the number */
3465 tmpi
= cnt_list
[j
].cnt
;
3471 tmps
= (char *)malloc (sz
* sizeof (char));
3472 sprintf (tmps
, "%s%d", cnt_list
[j
].name
, cnt_list
[j
].cnt
);
3475 * now compare to the list of reserved (by locked
3478 for (k
= 0; k
< lock_cnt
; k
++)
3481 (UNKNOWN (NAMEONPCB_NAME (locked_element_list
[k
])),
3492 if (strcmp (tmps
, NAMEONPCB_NAME (element_list
[i
])) != 0)
3494 fprintf (out
, "*RENAME* \"%s\" \"%s\"\n",
3495 NAMEONPCB_NAME (element_list
[i
]), tmps
);
3497 /* add this rename to our table of renames so we can update the netlist */
3498 was
[c_cnt
] = strdup (NAMEONPCB_NAME (element_list
[i
]));
3499 is
[c_cnt
] = strdup (tmps
);
3502 AddObjectToChangeNameUndoList (ELEMENT_TYPE
, NULL
, NULL
,
3504 NAMEONPCB_NAME (element_list
3507 ChangeObjectName (ELEMENT_TYPE
, element_list
[i
], NULL
, NULL
,
3511 /* we don't free tmps in this case because it is used */
3518 pcb_fprintf (out
, "*WARN* Element at %$md has no name.\n",
3519 element_list
[i
]->MarkX
, element_list
[i
]->MarkY
);
3526 /* restore the unique flag setting */
3528 SET_FLAG (UNIQUENAMEFLAG
, PCB
);
3533 /* update the netlist */
3534 AddNetlistLibToUndoList (&(PCB
->NetlistLib
));
3536 /* iterate over each net */
3537 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
3540 /* iterate over each pin on the net */
3541 for (j
= 0; j
< PCB
->NetlistLib
.Menu
[i
].EntryN
; j
++)
3544 /* figure out the pin number part from strings like U3-21 */
3545 tmps
= strdup (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3546 for (k
= 0; tmps
[k
] && tmps
[k
] != '-'; k
++);
3550 /* iterate over the list of changed reference designators */
3551 for (k
= 0; k
< c_cnt
; k
++)
3554 * if the pin needs to change, change it and quit
3555 * searching in the list.
3557 if (strcmp (tmps
, was
[k
]) == 0)
3559 free (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3560 PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
=
3561 (char *)malloc ((strlen (is
[k
]) + strlen (pin
) +
3562 2) * sizeof (char));
3563 sprintf (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
,
3564 "%s-%s", is
[k
], pin
);
3572 for (k
= 0; k
< c_cnt
; k
++)
3579 IncrementUndoSerialNumber ();
3580 SetChangedFlag (true);
3583 free (locked_element_list
);
3584 free (element_list
);
3590 /* --------------------------------------------------------------------------- */
3592 static const char ripup_syntax
[] = "RipUp(All|Selected|Element)";
3594 static const char ripup_help
[] =
3595 "Ripup auto-routed tracks, or convert an element to parts.";
3597 /* %start-doc actions RipUp
3602 Removes all lines and vias which were created by the autorouter.
3605 Removes all selected lines and vias which were created by the
3609 Converts the element under the cursor to parts (vias and lines). Note
3610 that this uses the highest numbered paste buffer.
3617 ActionRipUp (int argc
, char **argv
, Coord x
, Coord y
)
3619 char *function
= ARG (0);
3620 bool changed
= false;
3624 switch (GetFunctionID (function
))
3627 ALLLINE_LOOP (PCB
->Data
);
3629 if (TEST_FLAG (AUTOFLAG
, line
) && !TEST_FLAG (LOCKFLAG
, line
))
3631 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3636 ALLARC_LOOP (PCB
->Data
);
3638 if (TEST_FLAG (AUTOFLAG
, arc
) && !TEST_FLAG (LOCKFLAG
, arc
))
3640 RemoveObject (ARC_TYPE
, layer
, arc
, arc
);
3645 VIA_LOOP (PCB
->Data
);
3647 if (TEST_FLAG (AUTOFLAG
, via
) && !TEST_FLAG (LOCKFLAG
, via
))
3649 RemoveObject (VIA_TYPE
, via
, via
, via
);
3657 IncrementUndoSerialNumber ();
3658 SetChangedFlag (true);
3662 VISIBLELINE_LOOP (PCB
->Data
);
3664 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, line
)
3665 && !TEST_FLAG (LOCKFLAG
, line
))
3667 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3673 VIA_LOOP (PCB
->Data
);
3675 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, via
)
3676 && !TEST_FLAG (LOCKFLAG
, via
))
3678 RemoveObject (VIA_TYPE
, via
, via
, via
);
3685 IncrementUndoSerialNumber ();
3686 SetChangedFlag (true);
3691 void *ptr1
, *ptr2
, *ptr3
;
3693 if (SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
3694 &ptr1
, &ptr2
, &ptr3
) != NO_TYPE
)
3696 Note
.Buffer
= Settings
.BufferNumber
;
3697 SetBufferNumber (MAX_BUFFER
- 1);
3698 ClearBuffer (PASTEBUFFER
);
3699 CopyObjectToBuffer (PASTEBUFFER
->Data
, PCB
->Data
,
3700 ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3701 SmashBufferElement (PASTEBUFFER
);
3704 SaveUndoSerialNumber ();
3705 EraseObject (ELEMENT_TYPE
, ptr1
, ptr1
);
3706 MoveObjectToRemoveUndoList (ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3707 RestoreUndoSerialNumber ();
3708 CopyPastebufferToLayout (0, 0);
3709 SetBufferNumber (Note
.Buffer
);
3710 SetChangedFlag (true);
3719 /* --------------------------------------------------------------------------- */
3721 static const char addrats_syntax
[] = "AddRats(AllRats|SelectedRats|Close)";
3723 static const char addrats_help
[] = "Add one or more rat lines to the board.";
3725 /* %start-doc actions AddRats
3730 Create rat lines for all loaded nets that aren't already connected on
3734 Similarly, but only add rat lines for nets connected to selected pins
3738 Selects the shortest unselected rat on the board.
3745 ActionAddRats (int argc
, char **argv
, Coord x
, Coord y
)
3747 char *function
= ARG (0);
3753 if (Settings
.RatWarn
)
3755 switch (GetFunctionID (function
))
3758 if (AddAllRats (false, NULL
))
3759 SetChangedFlag (true);
3761 case F_SelectedRats
:
3763 if (AddAllRats (true, NULL
))
3764 SetChangedFlag (true);
3767 small
= SQUARE (MAX_COORD
);
3769 RAT_LOOP (PCB
->Data
);
3771 if (TEST_FLAG (SELECTEDFLAG
, line
))
3773 len
= SQUARE (line
->Point1
.X
- line
->Point2
.X
) +
3774 SQUARE (line
->Point1
.Y
- line
->Point2
.Y
);
3784 AddObjectToFlagUndoList (RATLINE_TYPE
, shorty
, shorty
, shorty
);
3785 SET_FLAG (SELECTEDFLAG
, shorty
);
3788 CenterDisplay ((shorty
->Point2
.X
+ shorty
->Point1
.X
) / 2,
3789 (shorty
->Point2
.Y
+ shorty
->Point1
.Y
) / 2);
3797 /* --------------------------------------------------------------------------- */
3799 static const char delete_syntax
[] =
3800 "Delete(Object|Selected)\n"
3801 "Delete(AllRats|SelectedRats)";
3803 static const char delete_help
[] = "Delete stuff.";
3805 /* %start-doc actions Delete
3810 ActionDelete (int argc
, char **argv
, Coord x
, Coord y
)
3812 char *function
= ARG (0);
3813 int id
= GetFunctionID (function
);
3815 Note
.X
= Crosshair
.X
;
3816 Note
.Y
= Crosshair
.Y
;
3818 if (id
== -1) /* no arg */
3820 if (RemoveSelected() == false)
3828 SetMode(REMOVE_MODE
);
3836 if (DeleteRats (false))
3837 SetChangedFlag (true);
3839 case F_SelectedRats
:
3840 if (DeleteRats (true))
3841 SetChangedFlag (true);
3848 /* --------------------------------------------------------------------------- */
3850 static const char deleterats_syntax
[] =
3851 "DeleteRats(AllRats|Selected|SelectedRats)";
3853 static const char deleterats_help
[] = "Delete rat lines.";
3855 /* %start-doc actions DeleteRats
3860 ActionDeleteRats (int argc
, char **argv
, Coord x
, Coord y
)
3862 char *function
= ARG (0);
3865 if (Settings
.RatWarn
)
3867 switch (GetFunctionID (function
))
3870 if (DeleteRats (false))
3871 SetChangedFlag (true);
3873 case F_SelectedRats
:
3875 if (DeleteRats (true))
3876 SetChangedFlag (true);
3883 /* --------------------------------------------------------------------------- */
3885 static const char autoplace_syntax
[] = "AutoPlaceSelected()";
3887 static const char autoplace_help
[] = "Auto-place selected components.";
3889 /* %start-doc actions AutoPlaceSelected
3891 Attempts to re-arrange the selected components such that the nets
3892 connecting them are minimized. Note that you cannot undo this.
3897 ActionAutoPlaceSelected (int argc
, char **argv
, Coord x
, Coord y
)
3900 if (gui
->confirm_dialog (_("Auto-placement can NOT be undone.\n"
3901 "Do you want to continue anyway?\n"), 0))
3903 if (AutoPlaceSelected ())
3904 SetChangedFlag (true);
3909 /* --------------------------------------------------------------------------- */
3911 static const char autoroute_syntax
[] = "AutoRoute(AllRats|SelectedRats)";
3913 static const char autoroute_help
[] = "Auto-route some or all rat lines.";
3915 /* %start-doc actions AutoRoute
3920 Attempt to autoroute all rats.
3923 Attempt to autoroute the selected rats.
3927 Before autorouting, it's important to set up a few things. First,
3928 make sure any layers you aren't using are disabled, else the
3929 autorouter may use them. Next, make sure the current line and via
3930 styles are set accordingly. Last, make sure "new lines clear
3931 polygons" is set, in case you eventually want to add a copper pour.
3933 Autorouting takes a while. During this time, the program may not be
3939 ActionAutoRoute (int argc
, char **argv
, Coord x
, Coord y
)
3941 char *function
= ARG (0);
3943 if (function
) /* one parameter */
3945 switch (GetFunctionID (function
))
3948 if (AutoRoute (false))
3949 SetChangedFlag (true);
3951 case F_SelectedRats
:
3953 if (AutoRoute (true))
3954 SetChangedFlag (true);
3961 /* --------------------------------------------------------------------------- */
3963 static const char markcrosshair_syntax
[] =
3965 "MarkCrosshair(Center)";
3967 static const char markcrosshair_help
[] = "Set/Reset the Crosshair mark.";
3969 /* %start-doc actions MarkCrosshair
3971 The ``mark'' is a small X-shaped target on the display which is
3972 treated like a second origin (the normal origin is the upper let
3973 corner of the board). The GUI will display a second set of
3974 coordinates for this mark, which tells you how far you are from it.
3976 If no argument is given, the mark is toggled - disabled if it was
3977 enabled, or enabled at the current cursor position of disabled. If
3978 the @code{Center} argument is given, the mark is moved to the current
3984 ActionMarkCrosshair (int argc
, char **argv
, Coord x
, Coord y
)
3986 char *function
= ARG (0);
3987 if (!function
|| !*function
)
3991 notify_mark_change (false);
3992 Marked
.status
= false;
3993 notify_mark_change (true);
3997 notify_mark_change (false);
3998 Marked
.status
= false;
3999 Marked
.status
= true;
4000 Marked
.X
= Crosshair
.X
;
4001 Marked
.Y
= Crosshair
.Y
;
4002 notify_mark_change (true);
4005 else if (GetFunctionID (function
) == F_Center
)
4007 notify_mark_change (false);
4008 Marked
.status
= true;
4009 Marked
.X
= Crosshair
.X
;
4010 Marked
.Y
= Crosshair
.Y
;
4011 notify_mark_change (true);
4016 /* --------------------------------------------------------------------------- */
4018 static const char changesize_syntax
[] =
4019 "ChangeSize(Object, delta)\n"
4020 "ChangeSize(SelectedObjects|Selected, delta)\n"
4021 "ChangeSize(SelectedLines|SelectedPins|SelectedVias, delta)\n"
4022 "ChangeSize(SelectedPads|SelectedTexts|SelectedNames, delta)\n"
4023 "ChangeSize(SelectedElements, delta)";
4025 static const char changesize_help
[] = "Changes the size of objects.";
4027 /* %start-doc actions ChangeSize
4029 For lines and arcs, this changes the width. For pins and vias, this
4030 changes the overall diameter of the copper annulus. For pads, this
4031 changes the width and, indirectly, the length. For texts and names,
4032 this changes the scaling factor. For elements, this changes the width
4033 of the silk layer lines and arcs for this element.
4038 ActionChangeSize (int argc
, char **argv
, Coord x
, Coord y
)
4040 char *function
= ARG (0);
4041 char *delta
= ARG (1);
4042 char *units
= ARG (2);
4043 bool absolute
; /* indicates if absolute size is given */
4046 if (function
&& delta
)
4048 value
= GetValue (delta
, units
, &absolute
);
4049 switch (GetFunctionID (function
))
4054 void *ptr1
, *ptr2
, *ptr3
;
4057 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
4058 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4059 if (TEST_FLAG (LOCKFLAG
, (PinTypePtr
) ptr2
))
4060 Message (_("Sorry, the object is locked\n"));
4061 if (ChangeObjectSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4062 SetChangedFlag (true);
4066 case F_SelectedVias
:
4067 if (ChangeSelectedSize (VIA_TYPE
, value
, absolute
))
4068 SetChangedFlag (true);
4071 case F_SelectedPins
:
4072 if (ChangeSelectedSize (PIN_TYPE
, value
, absolute
))
4073 SetChangedFlag (true);
4076 case F_SelectedPads
:
4077 if (ChangeSelectedSize (PAD_TYPE
, value
, absolute
))
4078 SetChangedFlag (true);
4081 case F_SelectedArcs
:
4082 if (ChangeSelectedSize (ARC_TYPE
, value
, absolute
))
4083 SetChangedFlag (true);
4086 case F_SelectedLines
:
4087 if (ChangeSelectedSize (LINE_TYPE
, value
, absolute
))
4088 SetChangedFlag (true);
4091 case F_SelectedTexts
:
4092 if (ChangeSelectedSize (TEXT_TYPE
, value
, absolute
))
4093 SetChangedFlag (true);
4096 case F_SelectedNames
:
4097 if (ChangeSelectedSize (ELEMENTNAME_TYPE
, value
, absolute
))
4098 SetChangedFlag (true);
4101 case F_SelectedElements
:
4102 if (ChangeSelectedSize (ELEMENT_TYPE
, value
, absolute
))
4103 SetChangedFlag (true);
4107 case F_SelectedObjects
:
4108 if (ChangeSelectedSize (CHANGESIZE_TYPES
, value
, absolute
))
4109 SetChangedFlag (true);
4116 /* --------------------------------------------------------------------------- */
4118 static const char changedrillsize_syntax
[] =
4119 "ChangeDrillSize(Object, delta)\n"
4120 "ChangeDrillSize(SelectedPins|SelectedVias|Selected|SelectedObjects, delta)";
4122 static const char changedrillsize_help
[] =
4123 "Changes the drilling hole size of objects.";
4125 /* %start-doc actions ChangeDrillSize
4130 ActionChange2ndSize (int argc
, char **argv
, Coord x
, Coord y
)
4132 char *function
= ARG (0);
4133 char *delta
= ARG (1);
4134 char *units
= ARG (2);
4138 if (function
&& delta
)
4140 value
= GetValue (delta
, units
, &absolute
);
4141 switch (GetFunctionID (function
))
4146 void *ptr1
, *ptr2
, *ptr3
;
4148 gui
->get_coords (_("Select an Object"), &x
, &y
);
4150 SearchScreen (x
, y
, CHANGE2NDSIZE_TYPES
,
4151 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4152 if (ChangeObject2ndSize
4153 (type
, ptr1
, ptr2
, ptr3
, value
, absolute
, true))
4154 SetChangedFlag (true);
4158 case F_SelectedVias
:
4159 if (ChangeSelected2ndSize (VIA_TYPE
, value
, absolute
))
4160 SetChangedFlag (true);
4163 case F_SelectedPins
:
4164 if (ChangeSelected2ndSize (PIN_TYPE
, value
, absolute
))
4165 SetChangedFlag (true);
4168 case F_SelectedObjects
:
4169 if (ChangeSelected2ndSize (PIN_TYPES
, value
, absolute
))
4170 SetChangedFlag (true);
4177 /* --------------------------------------------------------------------------- */
4179 static const char changeclearsize_syntax
[] =
4180 "ChangeClearSize(Object, delta)\n"
4181 "ChangeClearSize(SelectedPins|SelectedPads|SelectedVias, delta)\n"
4182 "ChangeClearSize(SelectedLines|SelectedArcs, delta\n"
4183 "ChangeClearSize(Selected|SelectedObjects, delta)";
4185 static const char changeclearsize_help
[] =
4186 "Changes the clearance size of objects.";
4188 /* %start-doc actions ChangeClearSize
4190 If the solder mask is currently showing, this action changes the
4191 solder mask clearance. If the mask is not showing, this action
4192 changes the polygon clearance.
4197 ActionChangeClearSize (int argc
, char **argv
, Coord x
, Coord y
)
4199 char *function
= ARG (0);
4200 char *delta
= ARG (1);
4201 char *units
= ARG (2);
4205 if (function
&& delta
)
4207 value
= 2 * GetValue (delta
, units
, &absolute
);
4208 switch (GetFunctionID (function
))
4213 void *ptr1
, *ptr2
, *ptr3
;
4215 gui
->get_coords (_("Select an Object"), &x
, &y
);
4218 CHANGECLEARSIZE_TYPES
, &ptr1
, &ptr2
,
4220 if (ChangeObjectClearSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4221 SetChangedFlag (true);
4224 case F_SelectedVias
:
4225 if (ChangeSelectedClearSize (VIA_TYPE
, value
, absolute
))
4226 SetChangedFlag (true);
4228 case F_SelectedPads
:
4229 if (ChangeSelectedClearSize (PAD_TYPE
, value
, absolute
))
4230 SetChangedFlag (true);
4232 case F_SelectedPins
:
4233 if (ChangeSelectedClearSize (PIN_TYPE
, value
, absolute
))
4234 SetChangedFlag (true);
4236 case F_SelectedLines
:
4237 if (ChangeSelectedClearSize (LINE_TYPE
, value
, absolute
))
4238 SetChangedFlag (true);
4240 case F_SelectedArcs
:
4241 if (ChangeSelectedClearSize (ARC_TYPE
, value
, absolute
))
4242 SetChangedFlag (true);
4245 case F_SelectedObjects
:
4246 if (ChangeSelectedClearSize (CHANGECLEARSIZE_TYPES
, value
, absolute
))
4247 SetChangedFlag (true);
4254 /* --------------------------------------------------------------------------- */
4256 static const char minmaskgap_syntax
[] =
4257 "MinMaskGap(delta)\n"
4258 "MinMaskGap(Selected, delta)";
4260 static const char minmaskgap_help
[] =
4261 "Ensures the mask is a minimum distance from pins and pads.";
4263 /* %start-doc actions MinMaskGap
4265 Checks all specified pins and/or pads, and increases the mask if
4266 needed to ensure a minimum distance between the pin or pad edge and
4272 ActionMinMaskGap (int argc
, char **argv
, Coord x
, Coord y
)
4274 char *function
= ARG (0);
4275 char *delta
= ARG (1);
4276 char *units
= ARG (2);
4283 if (strcasecmp (function
, "Selected") == 0)
4284 flags
= SELECTEDFLAG
;
4291 value
= 2 * GetValue (delta
, units
, &absolute
);
4293 SaveUndoSerialNumber ();
4294 ELEMENT_LOOP (PCB
->Data
);
4298 if (!TEST_FLAGS (flags
, pin
))
4300 if (pin
->Mask
< pin
->Thickness
+ value
)
4302 ChangeObjectMaskSize (PIN_TYPE
, element
, pin
, 0,
4303 pin
->Thickness
+ value
, 1);
4304 RestoreUndoSerialNumber ();
4310 if (!TEST_FLAGS (flags
, pad
))
4312 if (pad
->Mask
< pad
->Thickness
+ value
)
4314 ChangeObjectMaskSize (PAD_TYPE
, element
, pad
, 0,
4315 pad
->Thickness
+ value
, 1);
4316 RestoreUndoSerialNumber ();
4322 VIA_LOOP (PCB
->Data
);
4324 if (!TEST_FLAGS (flags
, via
))
4326 if (via
->Mask
&& via
->Mask
< via
->Thickness
+ value
)
4328 ChangeObjectMaskSize (VIA_TYPE
, via
, 0, 0, via
->Thickness
+ value
, 1);
4329 RestoreUndoSerialNumber ();
4333 RestoreUndoSerialNumber ();
4334 IncrementUndoSerialNumber ();
4338 /* --------------------------------------------------------------------------- */
4340 static const char mincleargap_syntax
[] =
4341 "MinClearGap(delta)\n"
4342 "MinClearGap(Selected, delta)";
4344 static const char mincleargap_help
[] =
4345 "Ensures that polygons are a minimum distance from objects.";
4347 /* %start-doc actions MinClearGap
4349 Checks all specified objects, and increases the polygon clearance if
4350 needed to ensure a minimum distance between their edges and the
4356 ActionMinClearGap (int argc
, char **argv
, Coord x
, Coord y
)
4358 char *function
= ARG (0);
4359 char *delta
= ARG (1);
4360 char *units
= ARG (2);
4367 if (strcasecmp (function
, "Selected") == 0)
4368 flags
= SELECTEDFLAG
;
4375 value
= 2 * GetValue (delta
, units
, &absolute
);
4377 SaveUndoSerialNumber ();
4378 ELEMENT_LOOP (PCB
->Data
);
4382 if (!TEST_FLAGS (flags
, pin
))
4384 if (pin
->Clearance
< value
)
4386 ChangeObjectClearSize (PIN_TYPE
, element
, pin
, 0,
4388 RestoreUndoSerialNumber ();
4394 if (!TEST_FLAGS (flags
, pad
))
4396 if (pad
->Clearance
< value
)
4398 ChangeObjectClearSize (PAD_TYPE
, element
, pad
, 0,
4400 RestoreUndoSerialNumber ();
4406 VIA_LOOP (PCB
->Data
);
4408 if (!TEST_FLAGS (flags
, via
))
4410 if (via
->Clearance
< value
)
4412 ChangeObjectClearSize (VIA_TYPE
, via
, 0, 0, value
, 1);
4413 RestoreUndoSerialNumber ();
4417 ALLLINE_LOOP (PCB
->Data
);
4419 if (!TEST_FLAGS (flags
, line
))
4421 if (line
->Clearance
< value
)
4423 ChangeObjectClearSize (LINE_TYPE
, layer
, line
, 0, value
, 1);
4424 RestoreUndoSerialNumber ();
4428 ALLARC_LOOP (PCB
->Data
);
4430 if (!TEST_FLAGS (flags
, arc
))
4432 if (arc
->Clearance
< value
)
4434 ChangeObjectClearSize (ARC_TYPE
, layer
, arc
, 0, value
, 1);
4435 RestoreUndoSerialNumber ();
4439 RestoreUndoSerialNumber ();
4440 IncrementUndoSerialNumber ();
4444 /* --------------------------------------------------------------------------- */
4446 static const char changepinname_syntax
[] =
4447 "ChangePinName(ElementName,PinNumber,PinName)";
4449 static const char changepinname_help
[] =
4450 "Sets the name of a specific pin on a specific element.";
4452 /* %start-doc actions ChangePinName
4454 This can be especially useful for annotating pin names from a
4455 schematic to the layout without requiring knowledge of the pcb file
4459 ChangePinName(U3, 7, VCC)
4465 ActionChangePinName (int argc
, char **argv
, Coord x
, Coord y
)
4468 char *refdes
, *pinnum
, *pinname
;
4472 AFAIL (changepinname
);
4479 ELEMENT_LOOP (PCB
->Data
);
4481 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
4485 if (NSTRCMP (pinnum
, pin
->Number
) == 0)
4487 AddObjectToChangeNameUndoList (PIN_TYPE
, NULL
, NULL
,
4490 * Note: we can't free() pin->Name first because
4491 * it is used in the undo list
4493 pin
->Name
= strdup (pinname
);
4494 SetChangedFlag (true);
4502 if (NSTRCMP (pinnum
, pad
->Number
) == 0)
4504 AddObjectToChangeNameUndoList (PAD_TYPE
, NULL
, NULL
,
4507 * Note: we can't free() pad->Name first because
4508 * it is used in the undo list
4510 pad
->Name
= strdup (pinname
);
4511 SetChangedFlag (true);
4520 * done with our action so increment the undo # if we actually
4526 defer_needs_update
= 1;
4529 IncrementUndoSerialNumber ();
4530 gui
->invalidate_all ();
4537 /* --------------------------------------------------------------------------- */
4539 static const char changename_syntax
[] =
4540 "ChangeName(Object)\n"
4541 "ChangeName(Layout|Layer)";
4543 static const char changename_help
[] = "Sets the name of objects.";
4545 /* %start-doc actions ChangeName
4550 Changes the name of the element under the cursor.
4553 Changes the name of the layout. This is printed on the fab drawings.
4556 Changes the name of the currently active layer.
4563 ActionChangeName (int argc
, char **argv
, Coord x
, Coord y
)
4565 char *function
= ARG (0);
4570 switch (GetFunctionID (function
))
4572 /* change the name of an object */
4576 void *ptr1
, *ptr2
, *ptr3
;
4578 gui
->get_coords (_("Select an Object"), &x
, &y
);
4580 SearchScreen (x
, y
, CHANGENAME_TYPES
,
4581 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4583 SaveUndoSerialNumber ();
4584 if (QueryInputAndChangeObjectName (type
, ptr1
, ptr2
, ptr3
))
4586 SetChangedFlag (true);
4587 if (type
== ELEMENT_TYPE
)
4589 RubberbandTypePtr ptr
;
4592 RestoreUndoSerialNumber ();
4593 Crosshair
.AttachedObject
.RubberbandN
= 0;
4594 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
4595 ptr
= Crosshair
.AttachedObject
.Rubberband
;
4596 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
;
4600 EraseRat ((RatTypePtr
) ptr
->Line
);
4601 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
4602 ptr
->Line
, ptr
->Line
,
4605 IncrementUndoSerialNumber ();
4613 /* change the layout's name */
4616 gui
->prompt_for (_("Enter the layout name:"), EMPTY (PCB
->Name
));
4617 /* NB: ChangeLayoutName takes ownership of the passed memory */
4618 if (name
&& ChangeLayoutName (name
))
4619 SetChangedFlag (true);
4622 /* change the name of the active layer */
4624 name
= gui
->prompt_for (_("Enter the layer name:"),
4625 EMPTY (CURRENT
->Name
));
4626 /* NB: ChangeLayerName takes ownership of the passed memory */
4627 if (name
&& ChangeLayerName (CURRENT
, name
))
4628 SetChangedFlag (true);
4636 /* --------------------------------------------------------------------------- */
4638 static const char morphpolygon_syntax
[] = "MorphPolygon(Object|Selected)";
4640 static const char morphpolygon_help
[] =
4641 "Converts dead polygon islands into separate polygons.";
4643 /* %start-doc actions MorphPolygon
4645 If a polygon is divided into unconnected "islands", you can use
4646 this command to convert the otherwise disappeared islands into
4647 separate polygons. Be sure the cursor is over a portion of the
4648 polygon that remains visible. Very small islands that may flake
4649 off are automatically deleted.
4654 ActionMorphPolygon (int argc
, char **argv
, Coord x
, Coord y
)
4656 char *function
= ARG (0);
4659 switch (GetFunctionID (function
))
4664 void *ptr1
, *ptr2
, *ptr3
;
4666 gui
->get_coords (_("Select an Object"), &x
, &y
);
4667 if ((type
= SearchScreen (x
, y
, POLYGON_TYPE
,
4668 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4670 MorphPolygon ((LayerType
*) ptr1
, (PolygonType
*) ptr3
);
4672 IncrementUndoSerialNumber ();
4677 case F_SelectedObjects
:
4678 ALLPOLYGON_LOOP (PCB
->Data
);
4680 if (TEST_FLAG (SELECTEDFLAG
, polygon
))
4681 MorphPolygon (layer
, polygon
);
4685 IncrementUndoSerialNumber ();
4692 /* --------------------------------------------------------------------------- */
4694 static const char togglehidename_syntax
[] =
4695 "ToggleHideName(Object|SelectedElements)";
4697 static const char togglehidename_help
[] =
4698 "Toggles the visibility of element names.";
4700 /* %start-doc actions ToggleHideName
4702 If names are hidden you won't see them on the screen and they will not
4703 appear on the silk layer when you print the layout.
4708 ActionToggleHideName (int argc
, char **argv
, Coord x
, Coord y
)
4710 char *function
= ARG (0);
4711 if (function
&& PCB
->ElementOn
)
4713 switch (GetFunctionID (function
))
4718 void *ptr1
, *ptr2
, *ptr3
;
4720 gui
->get_coords (_("Select an Object"), &x
, &y
);
4721 if ((type
= SearchScreen (x
, y
, ELEMENT_TYPE
,
4722 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4724 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr3
);
4725 EraseElementName ((ElementTypePtr
) ptr2
);
4726 TOGGLE_FLAG (HIDENAMEFLAG
, (ElementTypePtr
) ptr2
);
4727 DrawElementName ((ElementTypePtr
) ptr2
);
4729 IncrementUndoSerialNumber ();
4733 case F_SelectedElements
:
4736 bool changed
= false;
4737 ELEMENT_LOOP (PCB
->Data
);
4739 if ((TEST_FLAG (SELECTEDFLAG
, element
) ||
4740 TEST_FLAG (SELECTEDFLAG
,
4741 &NAMEONPCB_TEXT (element
)))
4742 && (FRONT (element
) || PCB
->InvisibleObjectsOn
))
4744 AddObjectToFlagUndoList (ELEMENT_TYPE
, element
,
4746 EraseElementName (element
);
4747 TOGGLE_FLAG (HIDENAMEFLAG
, element
);
4748 DrawElementName (element
);
4756 IncrementUndoSerialNumber ();
4764 /* --------------------------------------------------------------------------- */
4766 static const char changejoin_syntax
[] =
4767 "ChangeJoin(ToggleObject|SelectedLines|SelectedArcs|Selected)";
4769 static const char changejoin_help
[] =
4770 "Changes the join (clearance through polygons) of objects.";
4772 /* %start-doc actions ChangeJoin
4774 The join flag determines whether a line or arc, drawn to intersect a
4775 polygon, electrically connects to the polygon or not. When joined,
4776 the line/arc is simply drawn over the polygon, making an electrical
4777 connection. When not joined, a gap is drawn between the line and the
4778 polygon, insulating them from each other.
4783 ActionChangeJoin (int argc
, char **argv
, Coord x
, Coord y
)
4785 char *function
= ARG (0);
4788 switch (GetFunctionID (function
))
4790 case F_ToggleObject
:
4794 void *ptr1
, *ptr2
, *ptr3
;
4796 gui
->get_coords (_("Select an Object"), &x
, &y
);
4798 SearchScreen (x
, y
, CHANGEJOIN_TYPES
,
4799 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4800 if (ChangeObjectJoin (type
, ptr1
, ptr2
, ptr3
))
4801 SetChangedFlag (true);
4805 case F_SelectedLines
:
4806 if (ChangeSelectedJoin (LINE_TYPE
))
4807 SetChangedFlag (true);
4810 case F_SelectedArcs
:
4811 if (ChangeSelectedJoin (ARC_TYPE
))
4812 SetChangedFlag (true);
4816 case F_SelectedObjects
:
4817 if (ChangeSelectedJoin (CHANGEJOIN_TYPES
))
4818 SetChangedFlag (true);
4825 /* --------------------------------------------------------------------------- */
4827 static const char changesquare_syntax
[] =
4828 "ChangeSquare(ToggleObject)\n"
4829 "ChangeSquare(SelectedElements|SelectedPins)\n"
4830 "ChangeSquare(Selected|SelectedObjects)";
4832 static const char changesquare_help
[] =
4833 "Changes the square flag of pins and pads.";
4835 /* %start-doc actions ChangeSquare
4837 Note that @code{Pins} means both pins and pads.
4844 ActionChangeSquare (int argc
, char **argv
, Coord x
, Coord y
)
4846 char *function
= ARG (0);
4849 switch (GetFunctionID (function
))
4851 case F_ToggleObject
:
4855 void *ptr1
, *ptr2
, *ptr3
;
4857 gui
->get_coords (_("Select an Object"), &x
, &y
);
4859 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4860 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4861 if (ChangeObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4862 SetChangedFlag (true);
4866 case F_SelectedElements
:
4867 if (ChangeSelectedSquare (ELEMENT_TYPE
))
4868 SetChangedFlag (true);
4871 case F_SelectedPins
:
4872 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4873 SetChangedFlag (true);
4877 case F_SelectedObjects
:
4878 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4879 SetChangedFlag (true);
4886 /* --------------------------------------------------------------------------- */
4888 static const char setsquare_syntax
[] =
4889 "SetSquare(ToggleObject|SelectedElements|SelectedPins)";
4891 static const char setsquare_help
[] = "sets the square-flag of objects.";
4893 /* %start-doc actions SetSquare
4895 Note that @code{Pins} means pins and pads.
4902 ActionSetSquare (int argc
, char **argv
, Coord x
, Coord y
)
4904 char *function
= ARG (0);
4905 if (function
&& *function
)
4907 switch (GetFunctionID (function
))
4909 case F_ToggleObject
:
4913 void *ptr1
, *ptr2
, *ptr3
;
4915 gui
->get_coords (_("Select an Object"), &x
, &y
);
4917 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4918 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4919 if (SetObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4920 SetChangedFlag (true);
4924 case F_SelectedElements
:
4925 if (SetSelectedSquare (ELEMENT_TYPE
))
4926 SetChangedFlag (true);
4929 case F_SelectedPins
:
4930 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4931 SetChangedFlag (true);
4935 case F_SelectedObjects
:
4936 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4937 SetChangedFlag (true);
4944 /* --------------------------------------------------------------------------- */
4946 static const char clearsquare_syntax
[] =
4947 "ClearSquare(ToggleObject|SelectedElements|SelectedPins)";
4949 static const char clearsquare_help
[] =
4950 "Clears the square-flag of pins and pads.";
4952 /* %start-doc actions ClearSquare
4954 Note that @code{Pins} means pins and pads.
4961 ActionClearSquare (int argc
, char **argv
, Coord x
, Coord y
)
4963 char *function
= ARG (0);
4964 if (function
&& *function
)
4966 switch (GetFunctionID (function
))
4968 case F_ToggleObject
:
4972 void *ptr1
, *ptr2
, *ptr3
;
4974 gui
->get_coords (_("Select an Object"), &x
, &y
);
4976 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4977 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4978 if (ClrObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4979 SetChangedFlag (true);
4983 case F_SelectedElements
:
4984 if (ClrSelectedSquare (ELEMENT_TYPE
))
4985 SetChangedFlag (true);
4988 case F_SelectedPins
:
4989 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4990 SetChangedFlag (true);
4994 case F_SelectedObjects
:
4995 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4996 SetChangedFlag (true);
5003 /* --------------------------------------------------------------------------- */
5005 static const char changeoctagon_syntax
[] =
5006 "ChangeOctagon(Object|ToggleObject|SelectedObjects|Selected)\n"
5007 "ChangeOctagon(SelectedElements|SelectedPins|SelectedVias)";
5009 static const char changeoctagon_help
[] =
5010 "Changes the octagon-flag of pins and vias.";
5012 /* %start-doc actions ChangeOctagon
5019 ActionChangeOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5021 char *function
= ARG (0);
5024 switch (GetFunctionID (function
))
5026 case F_ToggleObject
:
5030 void *ptr1
, *ptr2
, *ptr3
;
5032 gui
->get_coords (_("Select an Object"), &x
, &y
);
5034 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5035 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5036 if (ChangeObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5037 SetChangedFlag (true);
5041 case F_SelectedElements
:
5042 if (ChangeSelectedOctagon (ELEMENT_TYPE
))
5043 SetChangedFlag (true);
5046 case F_SelectedPins
:
5047 if (ChangeSelectedOctagon (PIN_TYPE
))
5048 SetChangedFlag (true);
5051 case F_SelectedVias
:
5052 if (ChangeSelectedOctagon (VIA_TYPE
))
5053 SetChangedFlag (true);
5057 case F_SelectedObjects
:
5058 if (ChangeSelectedOctagon (PIN_TYPES
))
5059 SetChangedFlag (true);
5066 /* --------------------------------------------------------------------------- */
5068 static const char setoctagon_syntax
[] =
5069 "SetOctagon(Object|ToggleObject|SelectedElements|Selected)";
5071 static const char setoctagon_help
[] = "Sets the octagon-flag of objects.";
5073 /* %start-doc actions SetOctagon
5080 ActionSetOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5082 char *function
= ARG (0);
5085 switch (GetFunctionID (function
))
5087 case F_ToggleObject
:
5091 void *ptr1
, *ptr2
, *ptr3
;
5093 gui
->get_coords (_("Select an Object"), &x
, &y
);
5095 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5096 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5097 if (SetObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5098 SetChangedFlag (true);
5102 case F_SelectedElements
:
5103 if (SetSelectedOctagon (ELEMENT_TYPE
))
5104 SetChangedFlag (true);
5107 case F_SelectedPins
:
5108 if (SetSelectedOctagon (PIN_TYPE
))
5109 SetChangedFlag (true);
5112 case F_SelectedVias
:
5113 if (SetSelectedOctagon (VIA_TYPE
))
5114 SetChangedFlag (true);
5118 case F_SelectedObjects
:
5119 if (SetSelectedOctagon (PIN_TYPES
))
5120 SetChangedFlag (true);
5127 /* --------------------------------------------------------------------------- */
5129 static const char clearoctagon_syntax
[] =
5130 "ClearOctagon(ToggleObject|Object|SelectedObjects|Selected)\n"
5131 "ClearOctagon(SelectedElements|SelectedPins|SelectedVias)";
5133 static const char clearoctagon_help
[] =
5134 "Clears the octagon-flag of pins and vias.";
5136 /* %start-doc actions ClearOctagon
5143 ActionClearOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5145 char *function
= ARG (0);
5148 switch (GetFunctionID (function
))
5150 case F_ToggleObject
:
5154 void *ptr1
, *ptr2
, *ptr3
;
5156 gui
->get_coords (_("Select an Object"), &x
, &y
);
5158 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGEOCTAGON_TYPES
,
5159 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5160 if (ClrObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5161 SetChangedFlag (true);
5165 case F_SelectedElements
:
5166 if (ClrSelectedOctagon (ELEMENT_TYPE
))
5167 SetChangedFlag (true);
5170 case F_SelectedPins
:
5171 if (ClrSelectedOctagon (PIN_TYPE
))
5172 SetChangedFlag (true);
5175 case F_SelectedVias
:
5176 if (ClrSelectedOctagon (VIA_TYPE
))
5177 SetChangedFlag (true);
5181 case F_SelectedObjects
:
5182 if (ClrSelectedOctagon (PIN_TYPES
))
5183 SetChangedFlag (true);
5190 /* --------------------------------------------------------------------------- */
5192 static const char changehold_syntax
[] =
5193 "ChangeHole(ToggleObject|Object|SelectedVias|Selected)";
5195 static const char changehold_help
[] = "Changes the hole flag of objects.";
5197 /* %start-doc actions ChangeHole
5199 The "hole flag" of a via determines whether the via is a
5200 plated-through hole (not set), or an unplated hole (set).
5205 ActionChangeHole (int argc
, char **argv
, Coord x
, Coord y
)
5207 char *function
= ARG (0);
5210 switch (GetFunctionID (function
))
5212 case F_ToggleObject
:
5216 void *ptr1
, *ptr2
, *ptr3
;
5218 gui
->get_coords (_("Select an Object"), &x
, &y
);
5219 if ((type
= SearchScreen (x
, y
, VIA_TYPE
,
5220 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5221 && ChangeHole ((PinTypePtr
) ptr3
))
5222 IncrementUndoSerialNumber ();
5226 case F_SelectedVias
:
5228 if (ChangeSelectedHole ())
5229 SetChangedFlag (true);
5236 /* --------------------------------------------------------------------------- */
5238 static const char changepaste_syntax
[] =
5239 "ChangePaste(ToggleObject|Object|SelectedPads|Selected)";
5241 static const char changepaste_help
[] = "Changes the no paste flag of objects.";
5243 /* %start-doc actions ChangePaste
5245 The "no paste flag" of a pad determines whether the solderpaste
5246 stencil will have an opening for the pad (no set) or if there wil be
5247 no solderpaste on the pad (set). This is used for things such as
5253 ActionChangePaste (int argc
, char **argv
, Coord x
, Coord y
)
5255 char *function
= ARG (0);
5258 switch (GetFunctionID (function
))
5260 case F_ToggleObject
:
5264 void *ptr1
, *ptr2
, *ptr3
;
5266 gui
->get_coords (_("Select an Object"), &x
, &y
);
5267 if ((type
= SearchScreen (x
, y
, PAD_TYPE
,
5268 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5269 && ChangePaste ((PadTypePtr
) ptr3
))
5270 IncrementUndoSerialNumber ();
5274 case F_SelectedPads
:
5276 if (ChangeSelectedPaste ())
5277 SetChangedFlag (true);
5284 /* --------------------------------------------------------------------------- */
5286 static const char select_syntax
[] =
5287 "Select(Object|ToggleObject)\n"
5288 "Select(All|Block|Connection)\n"
5289 "Select(ElementByName|ObjectByName|PadByName|PinByName)\n"
5290 "Select(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5291 "Select(TextByName|ViaByName|NetByName)\n"
5292 "Select(TextByName|ViaByName|NetByName, Name)\n"
5295 static const char select_help
[] = "Toggles or sets the selection.";
5297 /* %start-doc actions Select
5309 These all rely on having a regular expression parser built into
5310 @code{pcb}. If the name is not specified then the user is prompted
5311 for a pattern, and all objects that match the pattern and are of the
5312 type specified are selected.
5316 Selects the object under the cursor.
5319 Selects all objects in a rectangle indicated by the cursor.
5322 Selects all objects on the board.
5325 Selects all connections with the ``found'' flag set.
5328 Converts the selected objects to an element. This uses the highest
5329 numbered paste buffer.
5336 ActionSelect (int argc
, char **argv
, Coord x
, Coord y
)
5338 char *function
= ARG (0);
5341 switch (GetFunctionID (function
))
5343 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5345 /* select objects by their names */
5346 case F_ElementByName
:
5347 type
= ELEMENT_TYPE
;
5349 case F_ObjectByName
:
5370 char *pattern
= ARG (1);
5374 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5376 if (SelectObjectByName (type
, pattern
, true))
5377 SetChangedFlag (true);
5378 if (ARG (1) == NULL
)
5383 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5385 /* select a single object */
5386 case F_ToggleObject
:
5388 if (SelectObject ())
5389 SetChangedFlag (true);
5392 /* all objects in block */
5397 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5398 Crosshair
.AttachedBox
.Point2
.X
);
5399 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5400 Crosshair
.AttachedBox
.Point2
.Y
);
5401 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5402 Crosshair
.AttachedBox
.Point2
.X
);
5403 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5404 Crosshair
.AttachedBox
.Point2
.Y
);
5405 notify_crosshair_change (false);
5407 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5408 SelectBlock (&box
, true))
5410 SetChangedFlag (true);
5411 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5413 notify_crosshair_change (true);
5417 /* select all visible objects */
5422 box
.X1
= -MAX_COORD
;
5423 box
.Y1
= -MAX_COORD
;
5426 if (SelectBlock (&box
, true))
5427 SetChangedFlag (true);
5431 /* all found connections */
5433 if (SelectConnection (true))
5436 IncrementUndoSerialNumber ();
5437 SetChangedFlag (true);
5444 Note
.Buffer
= Settings
.BufferNumber
;
5445 SetBufferNumber (MAX_BUFFER
- 1);
5446 ClearBuffer (PASTEBUFFER
);
5447 gui
->get_coords (_("Select the Element's Mark Location"), &x
, &y
);
5448 x
= GridFit (x
, PCB
->Grid
, PCB
->GridOffsetX
);
5449 y
= GridFit (y
, PCB
->Grid
, PCB
->GridOffsetY
);
5450 AddSelectedToBuffer (PASTEBUFFER
, x
, y
, true);
5451 SaveUndoSerialNumber ();
5453 ConvertBufferToElement (PASTEBUFFER
);
5454 RestoreUndoSerialNumber ();
5455 CopyPastebufferToLayout (x
, y
);
5456 SetBufferNumber (Note
.Buffer
);
5468 /* FLAG(have_regex,FlagHaveRegex,0) */
5470 FlagHaveRegex (int parm
)
5472 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5479 /* --------------------------------------------------------------------------- */
5481 static const char unselect_syntax
[] =
5482 "Unselect(All|Block|Connection)\n"
5483 "Unselect(ElementByName|ObjectByName|PadByName|PinByName)\n"
5484 "Unselect(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5485 "Unselect(TextByName|ViaByName)\n"
5486 "Unselect(TextByName|ViaByName, Name)\n";
5488 static const char unselect_help
[] =
5489 "Unselects the object at the pointer location or the specified objects.";
5491 /* %start-doc actions Unselect
5496 Unselect all objects.
5499 Unselect all objects in a rectangle given by the cursor.
5502 Unselect all connections with the ``found'' flag set.
5511 These all rely on having a regular expression parser built into
5512 @code{pcb}. If the name is not specified then the user is prompted
5513 for a pattern, and all objects that match the pattern and are of the
5514 type specified are unselected.
5522 ActionUnselect (int argc
, char **argv
, Coord x
, Coord y
)
5524 char *function
= ARG (0);
5527 switch (GetFunctionID (function
))
5529 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5531 /* select objects by their names */
5532 case F_ElementByName
:
5533 type
= ELEMENT_TYPE
;
5535 case F_ObjectByName
:
5556 char *pattern
= ARG (1);
5560 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5562 if (SelectObjectByName (type
, pattern
, false))
5563 SetChangedFlag (true);
5564 if (ARG (1) == NULL
)
5569 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5571 /* all objects in block */
5576 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5577 Crosshair
.AttachedBox
.Point2
.X
);
5578 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5579 Crosshair
.AttachedBox
.Point2
.Y
);
5580 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5581 Crosshair
.AttachedBox
.Point2
.X
);
5582 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5583 Crosshair
.AttachedBox
.Point2
.Y
);
5584 notify_crosshair_change (false);
5586 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5587 SelectBlock (&box
, false))
5589 SetChangedFlag (true);
5590 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5592 notify_crosshair_change (true);
5596 /* unselect all visible objects */
5601 box
.X1
= -MAX_COORD
;
5602 box
.Y1
= -MAX_COORD
;
5605 if (SelectBlock (&box
, false))
5606 SetChangedFlag (true);
5610 /* all found connections */
5612 if (SelectConnection (false))
5615 IncrementUndoSerialNumber ();
5616 SetChangedFlag (true);
5629 /* --------------------------------------------------------------------------- */
5631 static const char saveto_syntax
[] =
5632 "SaveTo(Layout|LayoutAs,filename)\n"
5633 "SaveTo(AllConnections|AllUnusedPins|ElementConnections,filename)\n"
5634 "SaveTo(PasteBuffer,filename)";
5636 static const char saveto_help
[] = "Saves data to a file.";
5638 /* %start-doc actions SaveTo
5643 Saves the current layout.
5646 Saves the current layout, and remembers the filename used.
5648 @item AllConnections
5649 Save all connections to a file.
5652 List all unused pins to a file.
5654 @item ElementConnections
5655 Save connections to the element at the cursor to a file.
5658 Save the content of the active Buffer to a file. This is the graphical way to create a footprint.
5665 ActionSaveTo (int argc
, char **argv
, Coord x
, Coord y
)
5673 if (strcasecmp (function
, "Layout") == 0)
5675 if (SavePCB (PCB
->Filename
) == 0)
5676 SetChangedFlag (false);
5683 if (strcasecmp (function
, "LayoutAs") == 0)
5685 if (SavePCB (name
) == 0)
5687 SetChangedFlag (false);
5688 free (PCB
->Filename
);
5689 PCB
->Filename
= strdup (name
);
5690 if (gui
->notify_filename_changed
!= NULL
)
5691 gui
->notify_filename_changed ();
5696 if (strcasecmp (function
, "AllConnections") == 0)
5700 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5702 LookupConnectionsToAllElements (fp
);
5704 SetChangedFlag (true);
5709 if (strcasecmp (function
, "AllUnusedPins") == 0)
5713 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5715 LookupUnusedPins (fp
);
5717 SetChangedFlag (true);
5722 if (strcasecmp (function
, "ElementConnections") == 0)
5724 ElementTypePtr element
;
5729 if ((SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
5730 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
5732 element
= (ElementTypePtr
) ptrtmp
;
5734 CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5736 LookupElementConnections (element
, fp
);
5738 SetChangedFlag (true);
5744 if (strcasecmp (function
, "PasteBuffer") == 0)
5746 return SaveBufferElements (name
);
5752 /* --------------------------------------------------------------------------- */
5754 static const char savesettings_syntax
[] =
5756 "SaveSettings(local)";
5758 static const char savesettings_help
[] = "Saves settings.";
5760 /* %start-doc actions SaveSettings
5762 If you pass no arguments, the settings are stored in
5763 @code{$HOME/.pcb/settings}. If you pass the word @code{local} they're
5764 saved in @code{./pcb.settings}.
5769 ActionSaveSettings (int argc
, char **argv
, Coord x
, Coord y
)
5771 int locally
= argc
> 0 ? (strncasecmp (argv
[0], "local", 5) == 0) : 0;
5772 hid_save_settings (locally
);
5776 /* --------------------------------------------------------------------------- */
5778 static const char loadfrom_syntax
[] =
5779 "LoadFrom(Layout|LayoutToBuffer|ElementToBuffer|Netlist|Revert,filename)";
5781 static const char loadfrom_help
[] = "Load layout data from a file.";
5783 /* %start-doc actions LoadFrom
5785 This action assumes you know what the filename is. The various GUIs
5786 should have a similar @code{Load} action where the filename is
5787 optional, and will provide their own file selection mechanism to let
5788 you choose the file name.
5793 Loads an entire PCB layout, replacing the current one.
5795 @item LayoutToBuffer
5796 Loads an entire PCB layout to the paste buffer.
5798 @item ElementToBuffer
5799 Loads the given element file into the paste buffer. Element files
5800 contain only a single @code{Element} definition, such as the
5801 ``newlib'' library uses.
5804 Loads a new netlist, replacing any current netlist.
5807 Re-loads the current layout from its disk file, reverting any changes
5815 ActionLoadFrom (int argc
, char **argv
, Coord x
, Coord y
)
5826 if (strcasecmp (function
, "ElementToBuffer") == 0)
5828 notify_crosshair_change (false);
5829 if (LoadElementToBuffer (PASTEBUFFER
, name
, true))
5830 SetMode (PASTEBUFFER_MODE
);
5831 notify_crosshair_change (true);
5834 else if (strcasecmp (function
, "LayoutToBuffer") == 0)
5836 notify_crosshair_change (false);
5837 if (LoadLayoutToBuffer (PASTEBUFFER
, name
))
5838 SetMode (PASTEBUFFER_MODE
);
5839 notify_crosshair_change (true);
5842 else if (strcasecmp (function
, "Layout") == 0)
5844 if (!PCB
->Changed
||
5845 gui
->confirm_dialog (_("OK to override layout data?"), 0))
5849 else if (strcasecmp (function
, "Netlist") == 0)
5851 if (PCB
->Netlistname
)
5852 free (PCB
->Netlistname
);
5853 PCB
->Netlistname
= StripWhiteSpaceAndDup (name
);
5854 FreeLibraryMemory (&PCB
->NetlistLib
);
5855 if (!ImportNetlist (PCB
->Netlistname
))
5858 else if (strcasecmp (function
, "Revert") == 0 && PCB
->Filename
5860 || gui
->confirm_dialog (_("OK to override changes?"), 0)))
5868 /* --------------------------------------------------------------------------- */
5870 static const char new_syntax
[] = "New([name])";
5872 static const char new_help
[] = "Starts a new layout.";
5874 /* %start-doc actions New
5876 If a name is not given, one is prompted for.
5881 ActionNew (int argc
, char **argv
, Coord x
, Coord y
)
5883 char *name
= ARG (0);
5885 if (!PCB
->Changed
|| gui
->confirm_dialog (_("OK to clear layout data?"), 0))
5888 name
= strdup (name
);
5890 name
= gui
->prompt_for (_("Enter the layout name:"), "");
5895 notify_crosshair_change (false);
5896 /* do emergency saving
5897 * clear the old struct and allocate memory for the new one
5899 if (PCB
->Changed
&& Settings
.SaveInTMP
)
5903 PCB
= CreateNewPCB (true);
5904 PCB
->Data
->LayerN
= DEF_LAYER
;
5905 CreateNewPCBPost (PCB
, 1);
5907 /* setup the new name and reset some values to default */
5911 ResetStackAndVisibility ();
5912 SetCrosshairRange (0, 0, PCB
->MaxWidth
, PCB
->MaxHeight
);
5913 CenterDisplay (PCB
->MaxWidth
/ 2, PCB
->MaxHeight
/ 2);
5916 hid_action ("PCBChanged");
5917 notify_crosshair_change (true);
5923 /* ---------------------------------------------------------------------------
5924 * no operation, just for testing purposes
5925 * syntax: Bell(volume)
5928 ActionBell (char *volume
)
5933 /* --------------------------------------------------------------------------- */
5935 static const char pastebuffer_syntax
[] =
5936 "PasteBuffer(AddSelected|Clear|1..MAX_BUFFER)\n"
5937 "PasteBuffer(Rotate, 1..3)\n"
5938 "PasteBuffer(Convert|Save|Restore|Mirror)\n"
5939 "PasteBuffer(ToLayout, X, Y, units)";
5941 static const char pastebuffer_help
[] =
5942 "Various operations on the paste buffer.";
5944 /* %start-doc actions PasteBuffer
5946 There are a number of paste buffers; the actual limit is a
5947 compile-time constant @code{MAX_BUFFER} in @file{globalconst.h}. It
5948 is currently @code{5}. One of these is the ``current'' paste buffer,
5949 often referred to as ``the'' paste buffer.
5954 Copies the selected objects to the current paste buffer.
5957 Remove all objects from the current paste buffer.
5960 Convert the current paste buffer to an element. Vias are converted to
5961 pins, lines are converted to pads.
5964 Convert any elements in the paste buffer back to vias and lines.
5967 Flip all objects in the paste buffer vertically (up/down flip). To mirror
5968 horizontally, combine this with rotations.
5971 Rotates the current buffer. The number to pass is 1..3, where 1 means
5972 90 degrees counter clockwise, 2 means 180 degrees, and 3 means 90
5973 degrees clockwise (270 CCW).
5976 Saves any elements in the current buffer to the indicated file.
5979 Pastes any elements in the current buffer to the indicated X, Y
5980 coordinates in the layout. The @code{X} and @code{Y} are treated like
5981 @code{delta} is for many other objects. For each, if it's prefixed by
5982 @code{+} or @code{-}, then that amount is relative to the last
5983 location. Otherwise, it's absolute. Units can be
5984 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
5985 units, currently 1/100 mil.
5989 Selects the given buffer to be the current paste buffer.
5996 ActionPasteBuffer (int argc
, char **argv
, Coord x
, Coord y
)
5998 char *function
= argc
? argv
[0] : (char *)"";
5999 char *sbufnum
= argc
> 1 ? argv
[1] : (char *)"";
6001 static char *default_file
= NULL
;
6004 notify_crosshair_change (false);
6007 switch (GetFunctionID (function
))
6009 /* clear contents of paste buffer */
6011 ClearBuffer (PASTEBUFFER
);
6014 /* copies objects to paste buffer */
6016 AddSelectedToBuffer (PASTEBUFFER
, 0, 0, false);
6019 /* converts buffer contents into an element */
6021 ConvertBufferToElement (PASTEBUFFER
);
6024 /* break up element for editing */
6026 SmashBufferElement (PASTEBUFFER
);
6031 MirrorBuffer (PASTEBUFFER
);
6037 RotateBuffer (PASTEBUFFER
, (BYTE
) atoi (sbufnum
));
6038 SetCrosshairRangeToBuffer ();
6043 if (PASTEBUFFER
->Data
->ElementN
== 0)
6045 Message (_("Buffer has no elements!\n"));
6051 name
= gui
->fileselect (_("Save Paste Buffer As ..."),
6052 _("Choose a file to save the contents of the\n"
6053 "paste buffer to.\n"),
6054 default_file
, ".fp", "footprint",
6059 free (default_file
);
6060 default_file
= NULL
;
6064 default_file
= strdup (name
);
6075 if ((exist
= fopen (name
, "r")))
6079 confirm_dialog (_("File exists! Ok to overwrite?"), 0))
6080 SaveBufferElements (name
);
6083 SaveBufferElements (name
);
6085 if (free_name
&& name
)
6092 static Coord oldx
= 0, oldy
= 0;
6100 else if (argc
== 3 || argc
== 4)
6102 x
= GetValue (ARG (1), ARG (3), &absolute
);
6105 y
= GetValue (ARG (2), ARG (3), &absolute
);
6111 notify_crosshair_change (true);
6112 AFAIL (pastebuffer
);
6117 if (CopyPastebufferToLayout (x
, y
))
6118 SetChangedFlag (true);
6125 int number
= atoi (function
);
6127 /* correct number */
6129 SetBufferNumber (number
- 1);
6134 notify_crosshair_change (true);
6138 /* --------------------------------------------------------------------------- */
6140 static const char undo_syntax
[] = "Undo()\n"
6143 static const char undo_help
[] = "Undo recent changes.";
6145 /* %start-doc actions Undo
6147 The unlimited undo feature of @code{Pcb} allows you to recover from
6148 most operations that materially affect you work. Calling
6149 @code{Undo()} without any parameter recovers from the last (non-undo)
6150 operation. @code{ClearList} is used to release the allocated
6151 memory. @code{ClearList} is called whenever a new layout is started or
6152 loaded. See also @code{Redo} and @code{Atomic}.
6154 Note that undo groups operations by serial number; changes with the
6155 same serial number will be undone (or redone) as a group. See
6161 ActionUndo (int argc
, char **argv
, Coord x
, Coord y
)
6163 char *function
= ARG (0);
6164 if (!function
|| !*function
)
6166 /* don't allow undo in the middle of an operation */
6167 if (Settings
.Mode
!= POLYGONHOLE_MODE
&&
6168 Crosshair
.AttachedObject
.State
!= STATE_FIRST
)
6170 if (Crosshair
.AttachedBox
.State
!= STATE_FIRST
6171 && Settings
.Mode
!= ARC_MODE
)
6173 /* undo the last operation */
6175 notify_crosshair_change (false);
6176 if ((Settings
.Mode
== POLYGON_MODE
||
6177 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6178 Crosshair
.AttachedPolygon
.PointN
)
6180 GoToPreviousPoint ();
6181 notify_crosshair_change (true);
6184 /* move anchor point if undoing during line creation */
6185 if (Settings
.Mode
== LINE_MODE
)
6187 if (Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6189 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6190 Undo (true); /* undo the connection find */
6191 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
6192 SetLocalRef (0, 0, false);
6193 notify_crosshair_change (true);
6196 if (Crosshair
.AttachedLine
.State
== STATE_THIRD
)
6199 void *ptr1
, *ptr3
, *ptrtmp
;
6201 /* this search is guaranteed to succeed */
6202 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6204 Crosshair
.AttachedLine
.Point1
.X
,
6205 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6206 ptr2
= (LineTypePtr
) ptrtmp
;
6208 /* save both ends of line */
6209 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point1
.X
;
6210 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point1
.Y
;
6211 if ((type
= Undo (true)))
6212 SetChangedFlag (true);
6213 /* check that the undo was of the right type */
6214 if ((type
& UNDO_CREATE
) == 0)
6216 /* wrong undo type, restore anchor points */
6217 Crosshair
.AttachedLine
.Point2
.X
=
6218 Crosshair
.AttachedLine
.Point1
.X
;
6219 Crosshair
.AttachedLine
.Point2
.Y
=
6220 Crosshair
.AttachedLine
.Point1
.Y
;
6221 notify_crosshair_change (true);
6224 /* move to new anchor */
6225 Crosshair
.AttachedLine
.Point1
.X
=
6226 Crosshair
.AttachedLine
.Point2
.X
;
6227 Crosshair
.AttachedLine
.Point1
.Y
=
6228 Crosshair
.AttachedLine
.Point2
.Y
;
6229 /* check if an intermediate point was removed */
6230 if (type
& UNDO_REMOVE
)
6232 /* this search should find the restored line */
6233 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6236 Crosshair
.AttachedLine
.Point2
.X
,
6237 Crosshair
.AttachedLine
.Point2
.Y
, 0);
6238 ptr2
= (LineTypePtr
) ptrtmp
;
6239 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6241 /* undo loses FOUNDFLAG */
6242 SET_FLAG(FOUNDFLAG
, ptr2
);
6243 DrawLine (CURRENT
, ptr2
);
6245 Crosshair
.AttachedLine
.Point1
.X
=
6246 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point2
.X
;
6247 Crosshair
.AttachedLine
.Point1
.Y
=
6248 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point2
.Y
;
6250 FitCrosshairIntoGrid (Crosshair
.X
, Crosshair
.Y
);
6251 AdjustAttachedObjects ();
6252 if (--addedLines
== 0)
6254 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
6255 lastLayer
= CURRENT
;
6259 /* this search is guaranteed to succeed too */
6260 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6263 Crosshair
.AttachedLine
.Point1
.X
,
6264 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6265 ptr2
= (LineTypePtr
) ptrtmp
;
6266 lastLayer
= (LayerTypePtr
) ptr1
;
6268 notify_crosshair_change (true);
6272 if (Settings
.Mode
== ARC_MODE
)
6274 if (Crosshair
.AttachedBox
.State
== STATE_SECOND
)
6276 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
6277 notify_crosshair_change (true);
6280 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
)
6282 void *ptr1
, *ptr2
, *ptr3
;
6284 /* guaranteed to succeed */
6285 SearchObjectByLocation (ARC_TYPE
, &ptr1
, &ptr2
, &ptr3
,
6286 Crosshair
.AttachedBox
.Point1
.X
,
6287 Crosshair
.AttachedBox
.Point1
.Y
, 0);
6288 bx
= GetArcEnds ((ArcTypePtr
) ptr2
);
6289 Crosshair
.AttachedBox
.Point1
.X
=
6290 Crosshair
.AttachedBox
.Point2
.X
= bx
->X1
;
6291 Crosshair
.AttachedBox
.Point1
.Y
=
6292 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y1
;
6293 AdjustAttachedObjects ();
6294 if (--addedLines
== 0)
6295 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
6298 /* undo the last destructive operation */
6300 SetChangedFlag (true);
6304 switch (GetFunctionID (function
))
6306 /* clear 'undo objects' list */
6308 ClearUndoList (false);
6312 notify_crosshair_change (true);
6316 /* --------------------------------------------------------------------------- */
6318 static const char redo_syntax
[] = "Redo()";
6320 static const char redo_help
[] = "Redo recent \"undo\" operations.";
6322 /* %start-doc actions Redo
6324 This routine allows you to recover from the last undo command. You
6325 might want to do this if you thought that undo was going to revert
6326 something other than what it actually did (in case you are confused
6327 about which operations are un-doable), or if you have been backing up
6328 through a long undo list and over-shoot your stopping point. Any
6329 change that is made since the undo in question will trim the redo
6330 list. For example if you add ten lines, then undo three of them you
6331 could use redo to put them back, but if you move a line on the board
6332 before performing the redo, you will lose the ability to "redo" the
6333 three "undone" lines.
6338 ActionRedo (int argc
, char **argv
, Coord x
, Coord y
)
6340 if (((Settings
.Mode
== POLYGON_MODE
||
6341 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6342 Crosshair
.AttachedPolygon
.PointN
) ||
6343 Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6345 notify_crosshair_change (false);
6348 SetChangedFlag (true);
6349 if (Settings
.Mode
== LINE_MODE
&&
6350 Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
6352 LineType
*line
= g_list_last (CURRENT
->Line
)->data
;
6353 Crosshair
.AttachedLine
.Point1
.X
=
6354 Crosshair
.AttachedLine
.Point2
.X
= line
->Point2
.X
;
6355 Crosshair
.AttachedLine
.Point1
.Y
=
6356 Crosshair
.AttachedLine
.Point2
.Y
= line
->Point2
.Y
;
6360 notify_crosshair_change (true);
6364 /* --------------------------------------------------------------------------- */
6366 static const char polygon_syntax
[] = "Polygon(Close|PreviousPoint)";
6368 static const char polygon_help
[] = "Some polygon related stuff.";
6370 /* %start-doc actions Polygon
6372 Polygons need a special action routine to make life easier.
6377 Creates the final segment of the polygon. This may fail if clipping
6378 to 45 degree lines is switched on, in which case a warning is issued.
6381 Resets the newly entered corner to the previous one. The Undo action
6382 will call Polygon(PreviousPoint) when appropriate to do so.
6389 ActionPolygon (int argc
, char **argv
, Coord x
, Coord y
)
6391 char *function
= ARG (0);
6392 if (function
&& Settings
.Mode
== POLYGON_MODE
)
6394 notify_crosshair_change (false);
6395 switch (GetFunctionID (function
))
6397 /* close open polygon if possible */
6402 /* go back to the previous point */
6403 case F_PreviousPoint
:
6404 GoToPreviousPoint ();
6407 notify_crosshair_change (true);
6412 /* --------------------------------------------------------------------------- */
6414 static const char routestyle_syntax
[] = "RouteStyle(1|2|3|4)";
6416 static const char routestyle_help
[] =
6417 "Copies the indicated routing style into the current sizes.";
6419 /* %start-doc actions RouteStyle
6424 ActionRouteStyle (int argc
, char **argv
, Coord x
, Coord y
)
6426 char *str
= ARG (0);
6427 RouteStyleType
*rts
;
6432 number
= atoi (str
);
6433 if (number
> 0 && number
<= NUM_STYLES
)
6435 rts
= &PCB
->RouteStyle
[number
- 1];
6436 SetLineSize (rts
->Thick
);
6437 SetViaSize (rts
->Diameter
, true);
6438 SetViaDrillingHole (rts
->Hole
, true);
6439 SetKeepawayWidth (rts
->Keepaway
);
6440 hid_action("RouteStylesChanged");
6447 /* --------------------------------------------------------------------------- */
6449 static const char moveobject_syntax
[] = "MoveObject(X,Y,dim)";
6451 static const char moveobject_help
[] = "Moves the object under the crosshair.";
6453 /* %start-doc actions MoveObject
6455 The @code{X} and @code{Y} are treated like @code{delta} is for many
6456 other objects. For each, if it's prefixed by @code{+} or @code{-},
6457 then that amount is relative. Otherwise, it's absolute. Units can be
6458 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
6459 units, currently 1/100 mil.
6464 ActionMoveObject (int argc
, char **argv
, Coord x
, Coord y
)
6466 char *x_str
= ARG (0);
6467 char *y_str
= ARG (1);
6468 char *units
= ARG (2);
6470 bool absolute1
, absolute2
;
6471 void *ptr1
, *ptr2
, *ptr3
;
6474 ny
= GetValue (y_str
, units
, &absolute1
);
6475 nx
= GetValue (x_str
, units
, &absolute2
);
6477 type
= SearchScreen (x
, y
, MOVE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6478 if (type
== NO_TYPE
)
6480 Message (_("Nothing found under crosshair\n"));
6487 Crosshair
.AttachedObject
.RubberbandN
= 0;
6488 if (TEST_FLAG (RUBBERBANDFLAG
, PCB
))
6489 LookupRubberbandLines (type
, ptr1
, ptr2
, ptr3
);
6490 if (type
== ELEMENT_TYPE
)
6491 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
6492 MoveObjectAndRubberband (type
, ptr1
, ptr2
, ptr3
, nx
, ny
);
6493 SetChangedFlag (true);
6497 /* --------------------------------------------------------------------------- */
6499 static const char movetocurrentlayer_syntax
[] =
6500 "MoveToCurrentLayer(Object|SelectedObjects)";
6502 static const char movetocurrentlayer_help
[] =
6503 "Moves objects to the current layer.";
6505 /* %start-doc actions MoveToCurrentLayer
6507 Note that moving an element from a component layer to a solder layer,
6508 or from solder to component, won't automatically flip it. Use the
6509 @code{Flip()} action to do that.
6514 ActionMoveToCurrentLayer (int argc
, char **argv
, Coord x
, Coord y
)
6516 char *function
= ARG (0);
6519 switch (GetFunctionID (function
))
6524 void *ptr1
, *ptr2
, *ptr3
;
6526 gui
->get_coords (_("Select an Object"), &x
, &y
);
6528 SearchScreen (x
, y
, MOVETOLAYER_TYPES
,
6529 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6530 if (MoveObjectToLayer (type
, ptr1
, ptr2
, ptr3
, CURRENT
, false))
6531 SetChangedFlag (true);
6535 case F_SelectedObjects
:
6537 if (MoveSelectedObjectsToLayer (CURRENT
))
6538 SetChangedFlag (true);
6546 static const char setsame_syntax
[] = "SetSame()";
6548 static const char setsame_help
[] =
6549 "Sets current layer and sizes to match indicated item.";
6551 /* %start-doc actions SetSame
6553 When invoked over any line, arc, polygon, or via, this changes the
6554 current layer to be the layer that item is on, and changes the current
6555 sizes (thickness, keepaway, drill, etc) according to that item.
6560 ActionSetSame (int argc
, char **argv
, Coord x
, Coord y
)
6562 void *ptr1
, *ptr2
, *ptr3
;
6564 LayerTypePtr layer
= CURRENT
;
6566 type
= SearchScreen (x
, y
, CLONE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6567 /* set layer current and size from line or arc */
6571 notify_crosshair_change (false);
6572 Settings
.LineThickness
= ((LineTypePtr
) ptr2
)->Thickness
;
6573 Settings
.Keepaway
= ((LineTypePtr
) ptr2
)->Clearance
/ 2;
6574 layer
= (LayerTypePtr
) ptr1
;
6575 if (Settings
.Mode
!= LINE_MODE
)
6576 SetMode (LINE_MODE
);
6577 notify_crosshair_change (true);
6578 hid_action ("RouteStylesChanged");
6582 notify_crosshair_change (false);
6583 Settings
.LineThickness
= ((ArcTypePtr
) ptr2
)->Thickness
;
6584 Settings
.Keepaway
= ((ArcTypePtr
) ptr2
)->Clearance
/ 2;
6585 layer
= (LayerTypePtr
) ptr1
;
6586 if (Settings
.Mode
!= ARC_MODE
)
6588 notify_crosshair_change (true);
6589 hid_action ("RouteStylesChanged");
6593 layer
= (LayerTypePtr
) ptr1
;
6597 notify_crosshair_change (false);
6598 Settings
.ViaThickness
= ((PinTypePtr
) ptr2
)->Thickness
;
6599 Settings
.ViaDrillingHole
= ((PinTypePtr
) ptr2
)->DrillingHole
;
6600 Settings
.Keepaway
= ((PinTypePtr
) ptr2
)->Clearance
/ 2;
6601 if (Settings
.Mode
!= VIA_MODE
)
6603 notify_crosshair_change (true);
6604 hid_action ("RouteStylesChanged");
6610 if (layer
!= CURRENT
)
6612 ChangeGroupVisibility (GetLayerNumber (PCB
->Data
, layer
), true, true);
6619 /* --------------------------------------------------------------------------- */
6621 static const char setflag_syntax
[] =
6622 "SetFlag(Object|Selected|SelectedObjects, flag)\n"
6623 "SetFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6624 "SetFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6625 "SetFlag(SelectedElements, flag)\n"
6626 "flag = square | octagon | thermal | join";
6628 static const char setflag_help
[] = "Sets flags on objects.";
6630 /* %start-doc actions SetFlag
6632 Turns the given flag on, regardless of its previous setting. See
6636 SetFlag(SelectedPins,thermal)
6642 ActionSetFlag (int argc
, char **argv
, Coord x
, Coord y
)
6644 char *function
= ARG (0);
6645 char *flag
= ARG (1);
6646 ChangeFlag (function
, flag
, 1, "SetFlag");
6650 /* --------------------------------------------------------------------------- */
6652 static const char clrflag_syntax
[] =
6653 "ClrFlag(Object|Selected|SelectedObjects, flag)\n"
6654 "ClrFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6655 "ClrFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6656 "ClrFlag(SelectedElements, flag)\n"
6657 "flag = square | octagon | thermal | join";
6659 static const char clrflag_help
[] = "Clears flags on objects.";
6661 /* %start-doc actions ClrFlag
6663 Turns the given flag off, regardless of its previous setting. See
6667 ClrFlag(SelectedLines,join)
6673 ActionClrFlag (int argc
, char **argv
, Coord x
, Coord y
)
6675 char *function
= ARG (0);
6676 char *flag
= ARG (1);
6677 ChangeFlag (function
, flag
, 0, "ClrFlag");
6681 /* --------------------------------------------------------------------------- */
6683 static const char changeflag_syntax
[] =
6684 "ChangeFlag(Object|Selected|SelectedObjects, flag, value)\n"
6685 "ChangeFlag(SelectedLines|SelectedPins|SelectedVias, flag, value)\n"
6686 "ChangeFlag(SelectedPads|SelectedTexts|SelectedNames, flag, value)\n"
6687 "ChangeFlag(SelectedElements, flag, value)\n"
6688 "flag = square | octagon | thermal | join\n"
6691 static const char changeflag_help
[] = "Sets or clears flags on objects.";
6693 /* %start-doc actions ChangeFlag
6695 Toggles the given flag on the indicated object(s). The flag may be
6696 one of the flags listed above (square, octagon, thermal, join). The
6697 value may be the number 0 or 1. If the value is 0, the flag is
6698 cleared. If the value is 1, the flag is set.
6703 ActionChangeFlag (int argc
, char **argv
, Coord x
, Coord y
)
6705 char *function
= ARG (0);
6706 char *flag
= ARG (1);
6707 int value
= argc
> 2 ? atoi (argv
[2]) : -1;
6708 if (value
!= 0 && value
!= 1)
6711 ChangeFlag (function
, flag
, value
, "ChangeFlag");
6717 ChangeFlag (char *what
, char *flag_name
, int value
, char *cmd_name
)
6719 bool (*set_object
) (int, void *, void *, void *);
6720 bool (*set_selected
) (int);
6722 if (NSTRCMP (flag_name
, "square") == 0)
6724 set_object
= value
? SetObjectSquare
: ClrObjectSquare
;
6725 set_selected
= value
? SetSelectedSquare
: ClrSelectedSquare
;
6727 else if (NSTRCMP (flag_name
, "octagon") == 0)
6729 set_object
= value
? SetObjectOctagon
: ClrObjectOctagon
;
6730 set_selected
= value
? SetSelectedOctagon
: ClrSelectedOctagon
;
6732 else if (NSTRCMP (flag_name
, "join") == 0)
6734 /* Note: these are backwards, because the flag is "clear" but
6735 the command is "join". */
6736 set_object
= value
? ClrObjectJoin
: SetObjectJoin
;
6737 set_selected
= value
? ClrSelectedJoin
: SetSelectedJoin
;
6741 Message (_("%s(): Flag \"%s\" is not valid\n"), cmd_name
, flag_name
);
6745 switch (GetFunctionID (what
))
6750 void *ptr1
, *ptr2
, *ptr3
;
6753 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
6754 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6755 if (TEST_FLAG (LOCKFLAG
, (PinTypePtr
) ptr2
))
6756 Message (_("Sorry, the object is locked\n"));
6757 if (set_object (type
, ptr1
, ptr2
, ptr3
))
6758 SetChangedFlag (true);
6762 case F_SelectedVias
:
6763 if (set_selected (VIA_TYPE
))
6764 SetChangedFlag (true);
6767 case F_SelectedPins
:
6768 if (set_selected (PIN_TYPE
))
6769 SetChangedFlag (true);
6772 case F_SelectedPads
:
6773 if (set_selected (PAD_TYPE
))
6774 SetChangedFlag (true);
6777 case F_SelectedLines
:
6778 if (set_selected (LINE_TYPE
))
6779 SetChangedFlag (true);
6782 case F_SelectedTexts
:
6783 if (set_selected (TEXT_TYPE
))
6784 SetChangedFlag (true);
6787 case F_SelectedNames
:
6788 if (set_selected (ELEMENTNAME_TYPE
))
6789 SetChangedFlag (true);
6792 case F_SelectedElements
:
6793 if (set_selected (ELEMENT_TYPE
))
6794 SetChangedFlag (true);
6798 case F_SelectedObjects
:
6799 if (set_selected (CHANGESIZE_TYPES
))
6800 SetChangedFlag (true);
6805 /* --------------------------------------------------------------------------- */
6807 static const char executefile_syntax
[] = "ExecuteFile(filename)";
6809 static const char executefile_help
[] = "Run actions from the given file.";
6811 /* %start-doc actions ExecuteFile
6813 Lines starting with @code{#} are ignored.
6818 ActionExecuteFile (int argc
, char **argv
, Coord x
, Coord y
)
6827 AFAIL (executefile
);
6831 if ((fp
= fopen (fname
, "r")) == NULL
)
6833 fprintf (stderr
, _("Could not open actions file \"%s\".\n"), fname
);
6838 defer_needs_update
= 0;
6839 while (fgets (line
, sizeof (line
), fp
) != NULL
)
6844 /* eat the trailing newline */
6845 while (*sp
&& *sp
!= '\r' && *sp
!= '\n')
6849 /* eat leading spaces and tabs */
6851 while (*sp
&& (*sp
== ' ' || *sp
== '\t'))
6855 * if we have anything left and its not a comment line
6859 if (*sp
&& *sp
!= '#')
6861 /*Message ("%s : line %-3d : \"%s\"\n", fname, n, sp);*/
6862 hid_parse_actions (sp
);
6867 if (defer_needs_update
)
6869 IncrementUndoSerialNumber ();
6870 gui
->invalidate_all ();
6876 /* --------------------------------------------------------------------------- */
6879 ActionPSCalib (int argc
, char **argv
, Coord x
, Coord y
)
6881 HID
*ps
= hid_find_exporter ("ps");
6882 ps
->calibrate (0.0,0.0);
6886 /* --------------------------------------------------------------------------- */
6888 static ElementType
*element_cache
= NULL
;
6890 static ElementType
*
6891 find_element_by_refdes (char *refdes
)
6894 && NAMEONPCB_NAME(element_cache
)
6895 && strcmp (NAMEONPCB_NAME(element_cache
), refdes
) == 0)
6896 return element_cache
;
6898 ELEMENT_LOOP (PCB
->Data
);
6900 if (NAMEONPCB_NAME(element
)
6901 && strcmp (NAMEONPCB_NAME(element
), refdes
) == 0)
6903 element_cache
= element
;
6904 return element_cache
;
6911 static AttributeType
*
6912 lookup_attr (AttributeListTypePtr list
, const char *name
)
6915 for (i
=0; i
<list
->Number
; i
++)
6916 if (strcmp (list
->List
[i
].name
, name
) == 0)
6917 return & list
->List
[i
];
6922 delete_attr (AttributeListTypePtr list
, AttributeType
*attr
)
6924 int idx
= attr
- list
->List
;
6925 if (idx
< 0 || idx
>= list
->Number
)
6927 if (list
->Number
- idx
> 1)
6928 memmove (attr
, attr
+1, (list
->Number
- idx
- 1) * sizeof(AttributeType
));
6932 /* ---------------------------------------------------------------- */
6933 static const char elementlist_syntax
[] = "ElementList(Start|Done|Need,<refdes>,<footprint>,<value>)";
6935 static const char elementlist_help
[] = "Adds the given element if it doesn't already exist.";
6937 /* %start-doc actions elementlist
6942 Indicates the start of an element list; call this before any Need
6946 Searches the board for an element with a matching refdes.
6948 If found, the value and footprint are updated.
6950 If not found, a new element is created with the given footprint and value.
6953 Compares the list of elements needed since the most recent
6954 @code{start} with the list of elements actually on the board. Any
6955 elements that weren't listed are selected, so that the user may delete
6962 static int number_of_footprints_not_found
;
6965 parse_layout_attribute_units (char *name
, int def
)
6967 const char *as
= AttributeGet (PCB
, name
);
6970 return GetValue (as
, NULL
, NULL
);
6974 ActionElementList (int argc
, char **argv
, Coord x
, Coord y
)
6976 ElementType
*e
= NULL
;
6977 char *refdes
, *value
, *footprint
, *old
;
6979 char *function
= argv
[0];
6982 printf("Entered ActionElementList, executing function %s\n", function
);
6985 if (strcasecmp (function
, "start") == 0)
6987 ELEMENT_LOOP (PCB
->Data
);
6989 CLEAR_FLAG (FOUNDFLAG
, element
);
6992 element_cache
= NULL
;
6993 number_of_footprints_not_found
= 0;
6997 if (strcasecmp (function
, "done") == 0)
6999 ELEMENT_LOOP (PCB
->Data
);
7001 if (TEST_FLAG (FOUNDFLAG
, element
))
7003 CLEAR_FLAG (FOUNDFLAG
, element
);
7005 else if (! EMPTY_STRING_P (NAMEONPCB_NAME (element
)))
7007 /* Unnamed elements should remain untouched */
7008 SET_FLAG (SELECTEDFLAG
, element
);
7012 if (number_of_footprints_not_found
> 0)
7013 gui
->confirm_dialog ("Not all requested footprints were found.\n"
7014 "See the message log for details",
7019 if (strcasecmp (function
, "need") != 0)
7020 AFAIL (elementlist
);
7023 AFAIL (elementlist
);
7032 args
[0] = footprint
;
7037 printf(" ... footprint = %s\n", footprint
);
7038 printf(" ... refdes = %s\n", refdes
);
7039 printf(" ... value = %s\n", value
);
7042 e
= find_element_by_refdes (refdes
);
7049 printf(" ... Footprint not on board, need to add it.\n");
7051 /* Not on board, need to add it. */
7052 if (LoadFootprint(argc
, args
, x
, y
))
7054 number_of_footprints_not_found
++;
7058 nx
= PCB
->MaxWidth
/ 2;
7059 ny
= PCB
->MaxHeight
/ 2;
7060 d
= MIN (PCB
->MaxWidth
, PCB
->MaxHeight
) / 10;
7062 nx
= parse_layout_attribute_units ("import::newX", nx
);
7063 ny
= parse_layout_attribute_units ("import::newY", ny
);
7064 d
= parse_layout_attribute_units ("import::disperse", d
);
7068 nx
+= rand () % (d
*2) - d
;
7069 ny
+= rand () % (d
*2) - d
;
7074 if (nx
>= PCB
->MaxWidth
)
7075 nx
= PCB
->MaxWidth
- 1;
7078 if (ny
>= PCB
->MaxHeight
)
7079 ny
= PCB
->MaxHeight
- 1;
7081 /* Place components onto center of board. */
7082 if (CopyPastebufferToLayout (nx
, ny
))
7083 SetChangedFlag (true);
7086 else if (e
&& strcmp (DESCRIPTION_NAME(e
), footprint
) != 0)
7089 printf(" ... Footprint on board, but different from footprint loaded.\n");
7095 /* Different footprint, we need to swap them out. */
7096 if (LoadFootprint(argc
, args
, x
, y
))
7098 number_of_footprints_not_found
++;
7102 er
= ElementOrientation (e
);
7103 pe
= PASTEBUFFER
->Data
->Element
->data
;
7105 MirrorElementCoordinates (PASTEBUFFER
->Data
, pe
, pe
->MarkY
*2 - PCB
->MaxHeight
);
7106 pr
= ElementOrientation (pe
);
7112 RotateElementLowLevel (PASTEBUFFER
->Data
, pe
, pe
->MarkX
, pe
->MarkY
, (er
-pr
+4)%4);
7114 for (i
=0; i
<MAX_ELEMENTNAMES
; i
++)
7116 pe
->Name
[i
].X
= e
->Name
[i
].X
- mx
+ pe
->MarkX
;
7117 pe
->Name
[i
].Y
= e
->Name
[i
].Y
- my
+ pe
->MarkY
;
7118 pe
->Name
[i
].Direction
= e
->Name
[i
].Direction
;
7119 pe
->Name
[i
].Scale
= e
->Name
[i
].Scale
;
7124 if (CopyPastebufferToLayout (mx
, my
))
7125 SetChangedFlag (true);
7128 /* Now reload footprint */
7129 element_cache
= NULL
;
7130 e
= find_element_by_refdes (refdes
);
7132 old
= ChangeElementText (PCB
, PCB
->Data
, e
, NAMEONPCB_INDEX
, strdup (refdes
));
7135 old
= ChangeElementText (PCB
, PCB
->Data
, e
, VALUE_INDEX
, strdup (value
));
7139 SET_FLAG (FOUNDFLAG
, e
);
7142 printf(" ... Leaving ActionElementList.\n");
7148 /* ---------------------------------------------------------------- */
7149 static const char elementsetattr_syntax
[] = "ElementSetAttr(refdes,name[,value])";
7151 static const char elementsetattr_help
[] = "Sets or clears an element-specific attribute.";
7153 /* %start-doc actions elementsetattr
7155 If a value is specified, the named attribute is added (if not already
7156 present) or changed (if it is) to the given value. If the value is
7157 not specified, the given attribute is removed if present.
7162 ActionElementSetAttr (int argc
, char **argv
, Coord x
, Coord y
)
7164 ElementType
*e
= NULL
;
7165 char *refdes
, *name
, *value
;
7166 AttributeType
*attr
;
7170 AFAIL (changepinname
);
7177 ELEMENT_LOOP (PCB
->Data
);
7179 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
7189 Message(_("Cannot change attribute of %s - element not found\n"), refdes
);
7193 attr
= lookup_attr (&e
->Attributes
, name
);
7198 attr
->value
= strdup (value
);
7200 if (attr
&& ! value
)
7202 delete_attr (& e
->Attributes
, attr
);
7206 CreateNewAttribute (& e
->Attributes
, name
, value
);
7212 /* ---------------------------------------------------------------- */
7213 static const char execcommand_syntax
[] = "ExecCommand(command)";
7215 static const char execcommand_help
[] = "Runs a command.";
7217 /* %start-doc actions execcommand
7219 Runs the given command, which is a system executable.
7224 ActionExecCommand (int argc
, char **argv
, Coord x
, Coord y
)
7230 AFAIL (execcommand
);
7235 if (system (command
))
7240 /* ---------------------------------------------------------------- */
7243 pcb_spawnvp (char **argv
)
7245 #ifdef HAVE__SPAWNVP
7246 int result
= _spawnvp (_P_WAIT
, argv
[0], (const char * const *) argv
);
7257 Message(_("Cannot fork!"));
7263 execvp (argv
[0], argv
);
7276 /* ---------------------------------------------------------------- */
7278 * Creates a new temporary file name. Hopefully the operating system
7279 * provides a mkdtemp() function to securily create a temporary
7280 * directory with mode 0700. If so then that directory is created and
7281 * the returned string is made up of the directory plus the name
7282 * variable. For example:
7284 * tempfile_name_new ("myfile") might return
7285 * "/var/tmp/pcb.123456/myfile".
7287 * If mkdtemp() is not available then 'name' is ignored and the
7288 * insecure tmpnam() function is used.
7290 * Files/names created with tempfile_name_new() should be unlinked
7291 * with tempfile_unlink to make sure the temporary directory is also
7292 * removed when mkdtemp() is used.
7295 tempfile_name_new (char * name
)
7297 char *tmpfile
= NULL
;
7299 char *tmpdir
, *mytmpdir
;
7303 assert ( name
!= NULL
);
7306 #define TEMPLATE "pcb.XXXXXXXX"
7309 tmpdir
= getenv ("TMPDIR");
7311 /* FIXME -- what about win32? */
7312 if (tmpdir
== NULL
) {
7316 mytmpdir
= (char *) malloc (sizeof(char) *
7321 if (mytmpdir
== NULL
) {
7322 fprintf (stderr
, "%s(): malloc failed()\n", __FUNCTION__
);
7327 (void)strcat (mytmpdir
, tmpdir
);
7328 (void)strcat (mytmpdir
, PCB_DIR_SEPARATOR_S
);
7329 (void)strcat (mytmpdir
, TEMPLATE
);
7330 if (mkdtemp (mytmpdir
) == NULL
) {
7331 fprintf (stderr
, "%s(): mkdtemp (\"%s\") failed\n", __FUNCTION__
, mytmpdir
);
7337 len
= strlen (mytmpdir
) + /* the temp directory name */
7338 1 + /* the directory sep. */
7339 strlen (name
) + /* the file name */
7340 1 /* the \0 termination */
7343 tmpfile
= (char *) malloc (sizeof (char) * len
);
7346 (void)strcat (tmpfile
, mytmpdir
);
7347 (void)strcat (tmpfile
, PCB_DIR_SEPARATOR_S
);
7348 (void)strcat (tmpfile
, name
);
7354 * tmpnam() uses a static buffer so strdup() the result right away
7355 * in case someone decides to create multiple temp names.
7357 tmpfile
= strdup (tmpnam (NULL
));
7360 /* Guile doesn't like \ separators */
7362 for (c
= tmpfile
; *c
; c
++)
7372 /* ---------------------------------------------------------------- */
7374 * Unlink a temporary file. If we have mkdtemp() then our temp file
7375 * lives in a temporary directory and we need to remove that directory
7379 tempfile_unlink (char * name
)
7382 /* SDB says: Want to keep old temp files for examiniation when debugging */
7391 /* it is possible that the file was never created so it is OK if the
7394 /* now figure out the directory name to remove */
7395 e
= strlen (name
) - 1;
7396 while (e
> 0 && name
[e
] != PCB_DIR_SEPARATOR_C
) {e
--;}
7398 dname
= strdup (name
);
7402 * at this point, e *should* point to the end of the directory part
7403 * but lets make sure.
7406 rc2
= rmdir (dname
);
7412 fprintf (stderr
, _("%s(): Unable to determine temp directory name from the temp file\n"),
7414 fprintf (stderr
, "%s(): \"%s\"\n",
7415 __FUNCTION__
, name
);
7419 /* name was allocated with malloc */
7424 * FIXME - should also return -1 if the temp file exists and was not
7432 int rc
= unlink (name
);
7435 fprintf (stderr
, _("Failed to unlink \"%s\"\n"), name
);
7446 /* ---------------------------------------------------------------- */
7447 static const char import_syntax
[] =
7449 "Import([gnetlist|make[,source,source,...]])\n"
7450 "Import(setnewpoint[,(mark|center|X,Y)])\n"
7451 "Import(setdisperse,D,units)\n";
7453 static const char import_help
[] = "Import schematics.";
7455 /* %start-doc actions Import
7457 Imports element and netlist data from the schematics (or some other
7458 source). The first parameter, which is optional, is the mode. If not
7459 specified, the @code{import::mode} attribute in the PCB is used.
7460 @code{gnetlist} means gnetlist is used to obtain the information from
7461 the schematics. @code{make} invokes @code{make}, assuming the user
7462 has a @code{Makefile} in the current directory. The @code{Makefile}
7463 will be invoked with the following variables set:
7468 The name of the .pcb file
7471 A space-separated list of source files
7474 The name of the file in which to put the command script, which may
7475 contain any @pcb{} actions. By default, this is a temporary file
7476 selected by @pcb{}, but if you specify an @code{import::outfile}
7477 attribute, that file name is used instead (and not automatically
7478 deleted afterwards).
7482 The target specified to be built is the first of these that apply:
7487 The target specified by an @code{import::target} attribute.
7490 The output file specified by an @code{import::outfile} attribute.
7493 If nothing else is specified, the target is @code{pcb_import}.
7497 If you specify an @code{import::makefile} attribute, then "-f <that
7498 file>" will be added to the command line.
7500 If you specify the mode, you may also specify the source files
7501 (schematics). If you do not specify any, the list of schematics is
7502 obtained by reading the @code{import::src@var{N}} attributes (like
7503 @code{import::src0}, @code{import::src1}, etc).
7505 For compatibility with future extensions to the import file format,
7506 the generated file @emph{must not} start with the two characters
7509 If a temporary file is needed the @code{TMPDIR} environment variable
7510 is used to select its location.
7512 Note that the programs @code{gnetlist} and @code{make} may be
7513 overridden by the user via the @code{make-program} and @code{gnetlist}
7514 @code{pcb} settings (i.e. in @code{~/.pcb/settings} or on the command
7517 If @pcb{} cannot determine which schematic(s) to import from, the GUI
7518 is called to let user choose (see @code{ImportGUI()}).
7520 Note that Import() doesn't delete anything - after an Import, elements
7521 which shouldn't be on the board are selected and may be removed once
7522 it's determined that the deletion is appropriate.
7524 If @code{Import()} is called with @code{setnewpoint}, then the location
7525 of new components can be specified. This is where parts show up when
7526 they're added to the board. The default is the center of the board.
7530 @item Import(setnewpoint)
7532 Prompts the user to click on the board somewhere, uses that point. If
7533 called by a hotkey, uses the current location of the crosshair.
7535 @item Import(setnewpoint,mark)
7537 Uses the location of the mark. If no mark is present, the point is
7540 @item Import(setnewpoint,center)
7542 Resets the point to the center of the board.
7544 @item Import(setnewpoint,X,Y,units)
7546 Sets the point to the specific coordinates given. Example:
7547 @code{Import(setnewpoint,50,25,mm)}
7551 Note that the X and Y locations are stored in attributes named
7552 @code{import::newX} and @code{import::newY} so you could change them
7553 manually if you wished.
7555 Calling @code{Import(setdisperse,D,units)} sets how much the newly
7556 placed elements are dispersed relative to the set point. For example,
7557 @code{Import(setdisperse,10,mm)} will offset each part randomly up to
7558 10mm away from the point. The default dispersion is 1/10th of the
7559 smallest board dimension. Dispersion is saved in the
7560 @code{import::disperse} attribute.
7565 ActionImport (int argc
, char **argv
, Coord x
, Coord y
)
7568 char **sources
= NULL
;
7572 printf("ActionImport: =========== Entering ActionImport ============\n");
7577 if (mode
&& strcasecmp (mode
, "setdisperse") == 0)
7586 const char *as
= AttributeGet (PCB
, "import::disperse");
7587 ds
= gui
->prompt_for(_("Enter dispersion:"), as
? as
: "0");
7591 sprintf(buf
, "%s%s", ds
, units
);
7592 AttributePut (PCB
, "import::disperse", buf
);
7595 AttributePut (PCB
, "import::disperse", ds
);
7596 if (ARG (1) == NULL
)
7601 if (mode
&& strcasecmp (mode
, "setnewpoint") == 0)
7603 const char *xs
, *ys
, *units
;
7613 gui
->get_coords (_("Click on a location"), &x
, &y
);
7615 else if (strcasecmp (xs
, "center") == 0)
7617 AttributeRemove (PCB
, "import::newX");
7618 AttributeRemove (PCB
, "import::newY");
7621 else if (strcasecmp (xs
, "mark") == 0)
7631 x
= GetValue (xs
, units
, NULL
);
7632 y
= GetValue (ys
, units
, NULL
);
7636 Message (_("Bad syntax for Import(setnewpoint)"));
7640 pcb_sprintf (buf
, "%$ms", x
);
7641 AttributePut (PCB
, "import::newX", buf
);
7642 pcb_sprintf (buf
, "%$ms", y
);
7643 AttributePut (PCB
, "import::newY", buf
);
7648 mode
= AttributeGet (PCB
, "import::mode");
7655 nsources
= argc
- 1;
7666 sprintf(sname
, "import::src%d", nsources
);
7667 src
= AttributeGet (PCB
, sname
);
7672 sources
= (char **) malloc ((nsources
+ 1) * sizeof (char *));
7676 sprintf(sname
, "import::src%d", nsources
);
7677 src
= AttributeGet (PCB
, sname
);
7678 sources
[nsources
] = src
;
7685 /* Replace .pcb with .sch and hope for the best. */
7686 char *pcbname
= PCB
->Filename
;
7688 char *dot
, *slash
, *bslash
;
7691 return hid_action("ImportGUI");
7693 schname
= (char *) malloc (strlen(pcbname
) + 5);
7694 strcpy (schname
, pcbname
);
7695 dot
= strchr (schname
, '.');
7696 slash
= strchr (schname
, '/');
7697 bslash
= strchr (schname
, '\\');
7698 if (dot
&& slash
&& dot
< slash
)
7700 if (dot
&& bslash
&& dot
< bslash
)
7704 strcat (schname
, ".sch");
7706 if (access (schname
, F_OK
))
7709 return hid_action("ImportGUI");
7712 sources
= (char **) malloc (2 * sizeof (char *));
7713 sources
[0] = schname
;
7718 if (strcasecmp (mode
, "gnetlist") == 0)
7720 char *tmpfile
= tempfile_name_new ("gnetlist_output");
7724 if (tmpfile
== NULL
) {
7725 Message (_("Could not create temp file"));
7729 cmd
= (char **) malloc ((7 + nsources
) * sizeof (char *));
7730 cmd
[0] = Settings
.GnetlistProgram
;
7736 for (i
=0; i
<nsources
; i
++)
7737 cmd
[6+i
] = sources
[i
];
7738 cmd
[6+nsources
] = NULL
;
7741 printf("ActionImport: =========== About to run gnetlist ============\n");
7742 printf("%s %s %s %s %s %s %s ...\n",
7743 cmd
[0], cmd
[1], cmd
[2], cmd
[3], cmd
[4], cmd
[5], cmd
[6]);
7746 if (pcb_spawnvp (cmd
))
7753 printf("ActionImport: =========== About to run ActionExecuteFile, file = %s ============\n", tmpfile
);
7758 ActionExecuteFile (1, cmd
, 0, 0);
7761 tempfile_unlink (tmpfile
);
7763 else if (strcasecmp (mode
, "make") == 0)
7765 int must_free_tmpfile
= 0;
7771 char *user_outfile
= NULL
;
7772 char *user_makefile
= NULL
;
7773 char *user_target
= NULL
;
7776 user_outfile
= AttributeGet (PCB
, "import::outfile");
7777 user_makefile
= AttributeGet (PCB
, "import::makefile");
7778 user_target
= AttributeGet (PCB
, "import::target");
7779 if (user_outfile
&& !user_target
)
7780 user_target
= user_outfile
;
7783 tmpfile
= user_outfile
;
7786 tmpfile
= tempfile_name_new ("gnetlist_output");
7787 if (tmpfile
== NULL
) {
7788 Message (_("Could not create temp file"));
7791 must_free_tmpfile
= 1;
7794 srclen
= sizeof("SRCLIST=") + 2;
7795 for (i
=0; i
<nsources
; i
++)
7796 srclen
+= strlen (sources
[i
]) + 2;
7797 srclist
= (char *) malloc (srclen
);
7798 strcpy (srclist
, "SRCLIST=");
7799 for (i
=0; i
<nsources
; i
++)
7802 strcat (srclist
, " ");
7803 strcat (srclist
, sources
[i
]);
7806 cmd
[0] = Settings
.MakeProgram
;
7808 cmd
[2] = Concat ("PCB=", PCB
->Filename
, NULL
);
7810 cmd
[4] = Concat ("OUT=", tmpfile
, NULL
);
7815 cmd
[i
++] = user_makefile
;
7817 cmd
[i
++] = user_target
? user_target
: (char *)"pcb_import";
7820 if (pcb_spawnvp (cmd
))
7822 if (must_free_tmpfile
)
7832 ActionExecuteFile (1, cmd
, 0, 0);
7837 if (must_free_tmpfile
)
7838 tempfile_unlink (tmpfile
);
7842 Message (_("Unknown import mode: %s\n"), mode
);
7847 AddAllRats (false, NULL
);
7850 printf("ActionImport: =========== Leaving ActionImport ============\n");
7856 /* ------------------------------------------------------------ */
7858 static const char attributes_syntax
[] =
7859 "Attributes(Layout|Layer|Element)\n"
7860 "Attributes(Layer,layername)";
7862 static const char attributes_help
[] =
7863 "Let the user edit the attributes of the layout, current or given\n"
7864 "layer, or selected element.";
7866 /* %start-doc actions Attributes
7868 This just pops up a dialog letting the user edit the attributes of the
7869 pcb, an element, or a layer.
7875 ActionAttributes (int argc
, char **argv
, Coord x
, Coord y
)
7877 char *function
= ARG (0);
7878 char *layername
= ARG (1);
7884 if (!gui
->edit_attributes
)
7886 Message (_("This GUI doesn't support Attribute Editing\n"));
7890 switch (GetFunctionID (function
))
7894 gui
->edit_attributes("Layout Attributes", &(PCB
->Attributes
));
7900 LayerType
*layer
= CURRENT
;
7905 for (i
=0; i
<max_copper_layer
; i
++)
7906 if (strcmp (PCB
->Data
->Layer
[i
].Name
, layername
) == 0)
7908 layer
= & (PCB
->Data
->Layer
[i
]);
7913 Message (_("No layer named %s\n"), layername
);
7917 buf
= (char *) malloc (strlen (layer
->Name
) + strlen ("Layer X Attributes"));
7918 sprintf (buf
, "Layer %s Attributes", layer
->Name
);
7919 gui
->edit_attributes(buf
, &(layer
->Attributes
));
7927 ElementType
*e
= NULL
;
7928 ELEMENT_LOOP (PCB
->Data
);
7930 if (TEST_FLAG (SELECTEDFLAG
, element
))
7939 Message (_("Too many elements selected\n"));
7945 gui
->get_coords (_("Click on an element"), &x
, &y
);
7947 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
7948 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
7949 e
= (ElementTypePtr
) ptrtmp
;
7952 Message (_("No element found there\n"));
7957 if (NAMEONPCB_NAME(e
))
7959 buf
= (char *) malloc (strlen (NAMEONPCB_NAME(e
)) + strlen ("Element X Attributes"));
7960 sprintf(buf
, "Element %s Attributes", NAMEONPCB_NAME(e
));
7964 buf
= strdup ("Unnamed Element Attributes");
7966 gui
->edit_attributes(buf
, &(e
->Attributes
));
7978 /* --------------------------------------------------------------------------- */
7980 HID_Action action_action_list
[] = {
7981 {"AddRats", 0, ActionAddRats
,
7982 addrats_help
, addrats_syntax
}
7984 {"Attributes", 0, ActionAttributes
,
7985 attributes_help
, attributes_syntax
}
7987 {"Atomic", 0, ActionAtomic
,
7988 atomic_help
, atomic_syntax
}
7990 {"AutoPlaceSelected", 0, ActionAutoPlaceSelected
,
7991 autoplace_help
, autoplace_syntax
}
7993 {"AutoRoute", 0, ActionAutoRoute
,
7994 autoroute_help
, autoroute_syntax
}
7996 {"ChangeClearSize", 0, ActionChangeClearSize
,
7997 changeclearsize_help
, changeclearsize_syntax
}
7999 {"ChangeDrillSize", 0, ActionChange2ndSize
,
8000 changedrillsize_help
, changedrillsize_syntax
}
8002 {"ChangeHole", 0, ActionChangeHole
,
8003 changehold_help
, changehold_syntax
}
8005 {"ChangeJoin", 0, ActionChangeJoin
,
8006 changejoin_help
, changejoin_syntax
}
8008 {"ChangeName", 0, ActionChangeName
,
8009 changename_help
, changename_syntax
}
8011 {"ChangePaste", 0, ActionChangePaste
,
8012 changepaste_help
, changepaste_syntax
}
8014 {"ChangePinName", 0, ActionChangePinName
,
8015 changepinname_help
, changepinname_syntax
}
8017 {"ChangeSize", 0, ActionChangeSize
,
8018 changesize_help
, changesize_syntax
}
8020 {"ChangeSquare", 0, ActionChangeSquare
,
8021 changesquare_help
, changesquare_syntax
}
8023 {"ChangeOctagon", 0, ActionChangeOctagon
,
8024 changeoctagon_help
, changeoctagon_syntax
}
8026 {"ClearSquare", 0, ActionClearSquare
,
8027 clearsquare_help
, clearsquare_syntax
}
8029 {"ClearOctagon", 0, ActionClearOctagon
,
8030 clearoctagon_help
, clearoctagon_syntax
}
8032 {"Connection", 0, ActionConnection
,
8033 connection_help
, connection_syntax
}
8035 {"Delete", 0, ActionDelete
,
8036 delete_help
, delete_syntax
}
8038 {"DeleteRats", 0, ActionDeleteRats
,
8039 deleterats_help
, deleterats_syntax
}
8041 {"DisperseElements", 0, ActionDisperseElements
,
8042 disperseelements_help
, disperseelements_syntax
}
8044 {"Display", 0, ActionDisplay
,
8045 display_help
, display_syntax
}
8047 {"DRC", 0, ActionDRCheck
,
8048 drc_help
, drc_syntax
}
8050 {"DumpLibrary", 0, ActionDumpLibrary
,
8051 dumplibrary_help
, dumplibrary_syntax
}
8053 {"ExecuteFile", 0, ActionExecuteFile
,
8054 executefile_help
, executefile_syntax
}
8056 {"Flip", N_("Click on Object or Flip Point"), ActionFlip
,
8057 flip_help
, flip_syntax
}
8059 {"LoadFrom", 0, ActionLoadFrom
,
8060 loadfrom_help
, loadfrom_syntax
}
8062 {"MarkCrosshair", 0, ActionMarkCrosshair
,
8063 markcrosshair_help
, markcrosshair_syntax
}
8065 {"Message", 0, ActionMessage
,
8066 message_help
, message_syntax
}
8068 {"MinMaskGap", 0, ActionMinMaskGap
,
8069 minmaskgap_help
, minmaskgap_syntax
}
8071 {"MinClearGap", 0, ActionMinClearGap
,
8072 mincleargap_help
, mincleargap_syntax
}
8074 {"Mode", 0, ActionMode
,
8075 mode_help
, mode_syntax
}
8077 {"MorphPolygon", 0, ActionMorphPolygon
,
8078 morphpolygon_help
, morphpolygon_syntax
}
8080 {"PasteBuffer", 0, ActionPasteBuffer
,
8081 pastebuffer_help
, pastebuffer_syntax
}
8083 {"Quit", 0, ActionQuit
,
8084 quit_help
, quit_syntax
}
8086 {"RemoveSelected", 0, ActionRemoveSelected
,
8087 removeselected_help
, removeselected_syntax
}
8089 {"Renumber", 0, ActionRenumber
,
8090 renumber_help
, renumber_syntax
}
8092 {"RipUp", 0, ActionRipUp
,
8093 ripup_help
, ripup_syntax
}
8095 {"Select", 0, ActionSelect
,
8096 select_help
, select_syntax
}
8098 {"Unselect", 0, ActionUnselect
,
8099 unselect_help
, unselect_syntax
}
8101 {"SaveSettings", 0, ActionSaveSettings
,
8102 savesettings_help
, savesettings_syntax
}
8104 {"SaveTo", 0, ActionSaveTo
,
8105 saveto_help
, saveto_syntax
}
8107 {"SetSquare", 0, ActionSetSquare
,
8108 setsquare_help
, setsquare_syntax
}
8110 {"SetOctagon", 0, ActionSetOctagon
,
8111 setoctagon_help
, setoctagon_syntax
}
8113 {"SetThermal", 0, ActionSetThermal
,
8114 setthermal_help
, setthermal_syntax
}
8116 {"SetValue", 0, ActionSetValue
,
8117 setvalue_help
, setvalue_syntax
}
8119 {"ToggleHideName", 0, ActionToggleHideName
,
8120 togglehidename_help
, togglehidename_syntax
}
8122 {"Undo", 0, ActionUndo
,
8123 undo_help
, undo_syntax
}
8125 {"Redo", 0, ActionRedo
,
8126 redo_help
, redo_syntax
}
8128 {"SetSame", N_("Select item to use attributes from"), ActionSetSame
,
8129 setsame_help
, setsame_syntax
}
8131 {"SetFlag", 0, ActionSetFlag
,
8132 setflag_help
, setflag_syntax
}
8134 {"ClrFlag", 0, ActionClrFlag
,
8135 clrflag_help
, clrflag_syntax
}
8137 {"ChangeFlag", 0, ActionChangeFlag
,
8138 changeflag_help
, changeflag_syntax
}
8140 {"Polygon", 0, ActionPolygon
,
8141 polygon_help
, polygon_syntax
}
8143 {"RouteStyle", 0, ActionRouteStyle
,
8144 routestyle_help
, routestyle_syntax
}
8146 {"MoveObject", N_("Select an Object"), ActionMoveObject
,
8147 moveobject_help
, moveobject_syntax
}
8149 {"MoveToCurrentLayer", 0, ActionMoveToCurrentLayer
,
8150 movetocurrentlayer_help
, movetocurrentlayer_syntax
}
8152 {"New", 0, ActionNew
,
8153 new_help
, new_syntax
}
8155 {"pscalib", 0, ActionPSCalib
}
8157 {"ElementList", 0, ActionElementList
,
8158 elementlist_help
, elementlist_syntax
}
8160 {"ElementSetAttr", 0, ActionElementSetAttr
,
8161 elementsetattr_help
, elementsetattr_syntax
}
8163 {"ExecCommand", 0, ActionExecCommand
,
8164 execcommand_help
, execcommand_syntax
}
8166 {"Import", 0, ActionImport
,
8167 import_help
, import_syntax
}
8171 REGISTER_ACTIONS (action_action_list
)