4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
6 * Copyright (C) 1997, 1998, 1999, 2000, 2001 Harry Eaton
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * Contact addresses for paper mail and Email:
23 * Harry Eaton, 6697 Buttonhole Ct, Columbia, MD 21044, USA
24 * haceaton@aplcomm.jhuapl.edu
28 /* action routines for output window
38 #include "autoplace.h"
39 #include "autoroute.h"
45 #include "crosshair.h"
59 /*#include "print.h"*/
64 #include "rubberband.h"
72 #include "pcb-printf.h"
75 #include <stdlib.h> /* rand() */
77 #ifdef HAVE_LIBDMALLOC
81 /* for fork() and friends */
86 #ifdef HAVE_SYS_WAIT_H
90 /* ---------------------------------------------------------------------------
120 F_ElementConnections
,
161 F_ResetLinesAndPolygons
,
162 F_ResetPinsViasAndPads
,
183 F_ToggleAllDirections
,
194 F_ToggleRubberBandMode
,
195 F_ToggleStartDirection
,
200 F_ToggleThindrawPoly
,
214 typedef struct /* used to identify subfunctions */
221 /* --------------------------------------------------------------------------- */
223 /* %start-doc actions 00delta
225 Many actions take a @code{delta} parameter as the last parameter,
226 which is an amount to change something. That @code{delta} may include
227 units, as an additional parameter, such as @code{Action(Object,5,mm)}.
228 If no units are specified, the default is PCB's native units
229 (currently 1/100 mil). Also, if the delta is prefixed by @code{+} or
230 @code{-}, the size is increased or decreased by that amount.
231 Otherwise, the size size is set to the given amount.
235 Action(Object,+0.5,mm)
239 Actions which take a @code{delta} parameter which do not accept all
240 these options will specify what they do take.
244 /* %start-doc actions 00objects
246 Many actions act on indicated objects on the board. They will have
247 parameters like @code{ToggleObject} or @code{SelectedVias} to indicate
248 what group of objects they act on. Unless otherwise specified, these
249 parameters are defined as follows:
255 Affects the object under the mouse pointer. If this action is invoked
256 from a menu or script, the user will be prompted to click on an
257 object, which is then the object affected.
260 @itemx SelectedObjects
262 Affects all objects which are currently selected. At least, all
263 selected objects for which the given action makes sense.
267 @itemx Selected@var{Type}
269 Affects all objects which are both selected and of the @var{Type} specified.
275 /* %start-doc actions 00macros
279 Pins, pads, and vias can have various shapes. All may be round. Pins
280 and pads may be square (obviously "square" pads are usually
281 rectangular). Pins and vias may be octagonal. When you change a
282 shape flag of an element, you actually change all of its pins and
285 Note that the square flag takes precedence over the octagon flag,
286 thus, if both the square and octagon flags are set, the object is
287 square. When the square flag is cleared, the pins and pads will be
288 either round or, if the octagon flag is set, octagonal.
294 /* ---------------------------------------------------------------------------
295 * some local identifiers
297 static PointType InsertedPoint
;
298 static LayerType
*lastLayer
;
311 bool Moving
; /* selected type clicked on */
312 int Hit
; /* move type clicked on */
319 static int defer_updates
= 0;
320 static int defer_needs_update
= 0;
322 static Cardinal polyIndex
= 0;
323 static bool saved_mode
= false;
324 #ifdef HAVE_LIBSTROKE
325 static bool mid_stroke
= false;
326 static BoxType StrokeBox
;
328 static FunctionType Functions
[] = {
329 {"AddSelected", F_AddSelected
},
331 {"AllConnections", F_AllConnections
},
332 {"AllRats", F_AllRats
},
333 {"AllUnusedPins", F_AllUnusedPins
},
337 {"Description", F_Description
},
338 {"Cancel", F_Cancel
},
339 {"Center", F_Center
},
341 {"ClearAndRedraw", F_ClearAndRedraw
},
342 {"ClearList", F_ClearList
},
344 {"Connection", F_Connection
},
345 {"Convert", F_Convert
},
347 {"CycleClip", F_CycleClip
},
348 {"CycleCrosshair", F_CycleCrosshair
},
349 {"DeleteRats", F_DeleteRats
},
351 {"DrillReport", F_DrillReport
},
352 {"Element", F_Element
},
353 {"ElementByName", F_ElementByName
},
354 {"ElementConnections", F_ElementConnections
},
355 {"ElementToBuffer", F_ElementToBuffer
},
356 {"Escape", F_Escape
},
358 {"FlipElement", F_FlipElement
},
359 {"FoundPins", F_FoundPins
},
361 {"InsertPoint", F_InsertPoint
},
363 {"Layout", F_Layout
},
364 {"LayoutAs", F_LayoutAs
},
365 {"LayoutToBuffer", F_LayoutToBuffer
},
367 {"LineSize", F_LineSize
},
369 {"Mirror", F_Mirror
},
371 {"NameOnPCB", F_NameOnPCB
},
372 {"Netlist", F_Netlist
},
373 {"NetByName", F_NetByName
},
375 {"Notify", F_Notify
},
376 {"Object", F_Object
},
377 {"ObjectByName", F_ObjectByName
},
378 {"PasteBuffer", F_PasteBuffer
},
379 {"PadByName", F_PadByName
},
380 {"PinByName", F_PinByName
},
381 {"PinOrPadName", F_PinOrPadName
},
382 {"Pinout", F_Pinout
},
383 {"Polygon", F_Polygon
},
384 {"PolygonHole", F_PolygonHole
},
385 {"PreviousPoint", F_PreviousPoint
},
386 {"RatsNest", F_RatsNest
},
387 {"Rectangle", F_Rectangle
},
388 {"Redraw", F_Redraw
},
389 {"Release", F_Release
},
390 {"Remove", F_Remove
},
391 {"RemoveSelected", F_RemoveSelected
},
392 {"Report", F_Report
},
394 {"ResetLinesAndPolygons", F_ResetLinesAndPolygons
},
395 {"ResetPinsViasAndPads", F_ResetPinsViasAndPads
},
396 {"Restore", F_Restore
},
397 {"Revert", F_Revert
},
398 {"Rotate", F_Rotate
},
400 {"Selected", F_Selected
},
401 {"SelectedArcs", F_SelectedArcs
},
402 {"SelectedElements", F_SelectedElements
},
403 {"SelectedLines", F_SelectedLines
},
404 {"SelectedNames", F_SelectedNames
},
405 {"SelectedObjects", F_SelectedObjects
},
406 {"SelectedPins", F_SelectedPins
},
407 {"SelectedPads", F_SelectedPads
},
408 {"SelectedRats", F_SelectedRats
},
409 {"SelectedTexts", F_SelectedTexts
},
410 {"SelectedVias", F_SelectedVias
},
411 {"Stroke", F_Stroke
},
413 {"TextByName", F_TextByName
},
414 {"TextScale", F_TextScale
},
415 {"Thermal", F_Thermal
},
416 {"ToLayout", F_ToLayout
},
417 {"Toggle45Degree", F_ToggleAllDirections
},
418 {"ToggleClearLine", F_ToggleClearLine
},
419 {"ToggleFullPoly", F_ToggleFullPoly
},
420 {"ToggleGrid", F_ToggleGrid
},
421 {"ToggleMask", F_ToggleMask
},
422 {"ToggleName", F_ToggleName
},
423 {"ToggleObject", F_ToggleObject
},
424 {"ToggleRubberBandMode", F_ToggleRubberBandMode
},
425 {"ToggleStartDirection", F_ToggleStartDirection
},
426 {"ToggleSnapPin", F_ToggleSnapPin
},
427 {"ToggleThindraw", F_ToggleThindraw
},
428 {"ToggleThindrawPoly", F_ToggleThindrawPoly
},
429 {"ToggleLockNames", F_ToggleLockNames
},
430 {"ToggleOnlyNames", F_ToggleOnlyNames
},
431 {"ToggleHideNames", F_ToggleHideNames
},
432 {"ToggleCheckPlanes", F_ToggleCheckPlanes
},
433 {"ToggleLocalRef", F_ToggleLocalRef
},
434 {"ToggleOrthoMove", F_ToggleOrthoMove
},
435 {"ToggleShowDRC", F_ToggleShowDRC
},
436 {"ToggleLiveRoute", F_ToggleLiveRoute
},
437 {"ToggleAutoDRC", F_ToggleAutoDRC
},
438 {"ToggleUniqueNames", F_ToggleUniqueNames
},
441 {"ViaByName", F_ViaByName
},
442 {"ViaSize", F_ViaSize
},
443 {"ViaDrillingHole", F_ViaDrillingHole
},
447 /* ---------------------------------------------------------------------------
448 * some local routines
450 static int GetFunctionID (String
);
451 static void AdjustAttachedBox (void);
452 static void NotifyLine (void);
453 static void NotifyBlock (void);
454 static void NotifyMode (void);
455 static void ClearWarnings (void);
456 #ifdef HAVE_LIBSTROKE
457 static void FinishStroke (void);
458 extern void stroke_init (void);
459 extern void stroke_record (int x
, int y
);
460 extern int stroke_trans (char *s
);
462 static void ChangeFlag (char *, char *, int, char *);
464 #define ARG(n) (argc > (n) ? argv[n] : NULL)
466 #ifdef HAVE_LIBSTROKE
468 /* ---------------------------------------------------------------------------
469 * FinishStroke - try to recognize the stroke sent
477 void *ptr1
, *ptr2
, *ptr3
;
480 if (stroke_trans (msg
))
486 if (Settings
.Mode
== LINE_MODE
)
496 RotateScreenObject (StrokeBox
.X1
, StrokeBox
.Y1
, SWAP_IDENT
? 1 : 3);
502 RotateScreenObject (StrokeBox
.X1
, StrokeBox
.Y1
, SWAP_IDENT
? 3 : 1);
508 SetMode (ARROW_MODE
);
533 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
= ((PinType
*) ptr2
)->X
;
901 Crosshair
.AttachedLine
.Point1
.Y
=
902 Crosshair
.AttachedLine
.Point2
.Y
= ((PinType
*) ptr2
)->Y
;
904 else if (type
== PAD_TYPE
)
906 PadType
*pad
= (PadType
*) 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
, (PinType
*) ptr2
))
1006 if (!Note
.Moving
&& (type
& SELECT_TYPES
) &&
1007 TEST_FLAG (SELECTEDFLAG
, (PinType
*) 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 ElementType
*element
= (ElementType
*) 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 SetChangedFlag (true);
1154 hid_actionl ("Report", "Object", NULL
);
1156 else if (type
!= NO_TYPE
)
1158 TextType
*thing
= (TextType
*) ptr3
;
1159 TOGGLE_FLAG (LOCKFLAG
, thing
);
1160 if (TEST_FLAG (LOCKFLAG
, thing
)
1161 && TEST_FLAG (SELECTEDFLAG
, thing
))
1163 /* this is not un-doable since LOCK isn't */
1164 CLEAR_FLAG (SELECTEDFLAG
, thing
);
1165 DrawObject (type
, ptr1
, ptr2
);
1168 SetChangedFlag (true);
1169 hid_actionl ("Report", "Object", NULL
);
1177 SearchScreen (Note
.X
, Note
.Y
, PIN_TYPES
, &ptr1
, &ptr2
,
1179 && !TEST_FLAG (HOLEFLAG
, (PinType
*) ptr3
))
1181 if (gui
->shift_is_pressed ())
1183 int tstyle
= GET_THERM (INDEXOFCURRENT
, (PinType
*) ptr3
);
1187 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, tstyle
);
1189 else if (GET_THERM (INDEXOFCURRENT
, (PinType
*) ptr3
))
1190 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, 0);
1192 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, PCB
->ThermStyle
);
1198 /* do update of position */
1200 if (Crosshair
.AttachedLine
.State
!= STATE_THIRD
)
1203 /* Remove anchor if clicking on start point;
1204 * this means we can't paint 0 length lines
1205 * which could be used for square SMD pads.
1206 * Instead use a very small delta, or change
1207 * the file after saving.
1209 if (Crosshair
.X
== Crosshair
.AttachedLine
.Point1
.X
1210 && Crosshair
.Y
== Crosshair
.AttachedLine
.Point1
.Y
)
1212 SetMode (LINE_MODE
);
1219 if ((line
= AddNet ()))
1222 AddObjectToCreateUndoList (RATLINE_TYPE
, line
, line
, line
);
1223 IncrementUndoSerialNumber ();
1225 Crosshair
.AttachedLine
.Point1
.X
=
1226 Crosshair
.AttachedLine
.Point2
.X
;
1227 Crosshair
.AttachedLine
.Point1
.Y
=
1228 Crosshair
.AttachedLine
.Point2
.Y
;
1234 /* create line if both ends are determined && length != 0 */
1237 int maybe_found_flag
;
1240 && Crosshair
.AttachedLine
.Point1
.X
==
1241 Crosshair
.AttachedLine
.Point2
.X
1242 && Crosshair
.AttachedLine
.Point1
.Y
==
1243 Crosshair
.AttachedLine
.Point2
.Y
1244 && (Crosshair
.AttachedLine
.Point2
.X
!= Note
.X
1245 || Crosshair
.AttachedLine
.Point2
.Y
!= Note
.Y
))
1247 /* We will only need to paint the second line segment.
1248 Since we only check for vias on the first segment,
1249 swap them so the non-empty segment is the first segment. */
1250 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1251 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1254 if (TEST_FLAG (AUTODRCFLAG
, PCB
)
1255 && ! TEST_SILK_LAYER (CURRENT
))
1256 maybe_found_flag
= FOUNDFLAG
;
1258 maybe_found_flag
= 0;
1260 if ((Crosshair
.AttachedLine
.Point1
.X
!=
1261 Crosshair
.AttachedLine
.Point2
.X
1262 || Crosshair
.AttachedLine
.Point1
.Y
!=
1263 Crosshair
.AttachedLine
.Point2
.Y
)
1265 CreateDrawnLineOnLayer (CURRENT
,
1266 Crosshair
.AttachedLine
.Point1
.X
,
1267 Crosshair
.AttachedLine
.Point1
.Y
,
1268 Crosshair
.AttachedLine
.Point2
.X
,
1269 Crosshair
.AttachedLine
.Point2
.Y
,
1270 Settings
.LineThickness
,
1271 2 * Settings
.Keepaway
,
1272 MakeFlags (maybe_found_flag
|
1275 PCB
) ? CLEARLINEFLAG
:
1281 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1282 DrawLine (CURRENT
, line
);
1283 /* place a via if vias are visible, the layer is
1284 in a new group since the last line and there
1285 isn't a pin already here */
1286 if (PCB
->ViaOn
&& GetLayerGroupNumberByPointer (CURRENT
) !=
1287 GetLayerGroupNumberByPointer (lastLayer
) &&
1288 SearchObjectByLocation (PIN_TYPES
, &ptr1
, &ptr2
, &ptr3
,
1289 Crosshair
.AttachedLine
.Point1
.X
,
1290 Crosshair
.AttachedLine
.Point1
.Y
,
1291 Settings
.ViaThickness
/ 2) ==
1294 CreateNewVia (PCB
->Data
,
1295 Crosshair
.AttachedLine
.Point1
.X
,
1296 Crosshair
.AttachedLine
.Point1
.Y
,
1297 Settings
.ViaThickness
,
1298 2 * Settings
.Keepaway
, 0,
1299 Settings
.ViaDrillingHole
, NULL
,
1300 NoFlags ())) != NULL
)
1302 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1305 /* copy the coordinates */
1306 Crosshair
.AttachedLine
.Point1
.X
=
1307 Crosshair
.AttachedLine
.Point2
.X
;
1308 Crosshair
.AttachedLine
.Point1
.Y
=
1309 Crosshair
.AttachedLine
.Point2
.Y
;
1310 IncrementUndoSerialNumber ();
1311 lastLayer
= CURRENT
;
1313 if (PCB
->Clipping
&& (Note
.X
!= Crosshair
.AttachedLine
.Point2
.X
1315 Crosshair
.AttachedLine
.Point2
.Y
)
1317 CreateDrawnLineOnLayer (CURRENT
,
1318 Crosshair
.AttachedLine
.Point2
.X
,
1319 Crosshair
.AttachedLine
.Point2
.Y
,
1321 Settings
.LineThickness
,
1322 2 * Settings
.Keepaway
,
1323 MakeFlags ((TEST_FLAG
1325 PCB
) ? FOUNDFLAG
: 0) |
1328 PCB
) ? CLEARLINEFLAG
:
1332 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1333 IncrementUndoSerialNumber ();
1334 DrawLine (CURRENT
, line
);
1335 /* move to new start point */
1336 Crosshair
.AttachedLine
.Point1
.X
= Note
.X
;
1337 Crosshair
.AttachedLine
.Point1
.Y
= Note
.Y
;
1338 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1339 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1340 if (TEST_FLAG (SWAPSTARTDIRFLAG
, PCB
))
1349 case RECTANGLE_MODE
:
1350 /* do update of position */
1353 /* create rectangle if both corners are determined
1354 * and width, height are != 0
1356 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
1357 Crosshair
.AttachedBox
.Point1
.X
!= Crosshair
.AttachedBox
.Point2
.X
&&
1358 Crosshair
.AttachedBox
.Point1
.Y
!= Crosshair
.AttachedBox
.Point2
.Y
)
1360 PolygonType
*polygon
;
1362 int flags
= CLEARPOLYFLAG
;
1363 if (TEST_FLAG (NEWFULLPOLYFLAG
, PCB
))
1364 flags
|= FULLPOLYFLAG
;
1365 if ((polygon
= CreateNewPolygonFromRectangle (CURRENT
,
1367 AttachedBox
.Point1
.X
,
1369 AttachedBox
.Point1
.Y
,
1371 AttachedBox
.Point2
.X
,
1373 AttachedBox
.Point2
.Y
,
1378 AddObjectToCreateUndoList (POLYGON_TYPE
, CURRENT
,
1380 IncrementUndoSerialNumber ();
1381 DrawPolygon (CURRENT
, polygon
);
1385 /* reset state to 'first corner' */
1386 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
1394 if ((string
= gui
->prompt_for (_("Enter text:"), "")) != NULL
)
1396 if (strlen(string
) > 0)
1399 int flag
= CLEARLINEFLAG
;
1401 if (GetLayerGroupNumberByNumber (INDEXOFCURRENT
) ==
1402 GetLayerGroupNumberByNumber (solder_silk_layer
))
1403 flag
|= ONSOLDERFLAG
;
1404 if ((text
= CreateNewText (CURRENT
, &PCB
->Font
, Note
.X
,
1405 Note
.Y
, 0, Settings
.TextScale
,
1406 string
, MakeFlags (flag
))) != NULL
)
1408 AddObjectToCreateUndoList (TEXT_TYPE
, CURRENT
, text
, text
);
1409 IncrementUndoSerialNumber ();
1410 DrawText (CURRENT
, text
);
1421 PointType
*points
= Crosshair
.AttachedPolygon
.Points
;
1422 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1424 /* do update of position; use the 'LINE_MODE' mechanism */
1427 /* check if this is the last point of a polygon */
1429 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1430 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1432 CopyAttachedPolygonToLayer ();
1437 /* create new point if it's the first one or if it's
1438 * different to the last one
1441 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1442 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1444 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1445 Crosshair
.AttachedLine
.Point2
.X
,
1446 Crosshair
.AttachedLine
.Point2
.Y
);
1448 /* copy the coordinates */
1449 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1450 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1455 case POLYGONHOLE_MODE
:
1457 switch (Crosshair
.AttachedObject
.State
)
1459 /* first notify, lookup object */
1461 Crosshair
.AttachedObject
.Type
=
1462 SearchScreen (Note
.X
, Note
.Y
, POLYGON_TYPE
,
1463 &Crosshair
.AttachedObject
.Ptr1
,
1464 &Crosshair
.AttachedObject
.Ptr2
,
1465 &Crosshair
.AttachedObject
.Ptr3
);
1467 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1469 if (TEST_FLAG (LOCKFLAG
, (PolygonType
*)
1470 Crosshair
.AttachedObject
.Ptr2
))
1472 Message (_("Sorry, the object is locked\n"));
1473 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1477 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1481 /* second notify, insert new point into object */
1484 PointType
*points
= Crosshair
.AttachedPolygon
.Points
;
1485 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1486 POLYAREA
*original
, *new_hole
, *result
;
1489 /* do update of position; use the 'LINE_MODE' mechanism */
1492 /* check if this is the last point of a polygon */
1494 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1495 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1497 /* Create POLYAREAs from the original polygon
1498 * and the new hole polygon */
1499 original
= PolygonToPoly ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
);
1500 new_hole
= PolygonToPoly (&Crosshair
.AttachedPolygon
);
1502 /* Subtract the hole from the original polygon shape */
1503 poly_Boolean_free (original
, new_hole
, &result
, PBO_SUB
);
1505 /* Convert the resulting polygon(s) into a new set of nodes
1506 * and place them on the page. Delete the original polygon.
1508 SaveUndoSerialNumber ();
1509 Flags
= ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
)->Flags
;
1510 PolyToPolygonsOnLayer (PCB
->Data
, (LayerType
*)Crosshair
.AttachedObject
.Ptr1
,
1512 RemoveObject (POLYGON_TYPE
,
1513 Crosshair
.AttachedObject
.Ptr1
,
1514 Crosshair
.AttachedObject
.Ptr2
,
1515 Crosshair
.AttachedObject
.Ptr3
);
1516 RestoreUndoSerialNumber ();
1517 IncrementUndoSerialNumber ();
1520 /* reset state of attached line */
1521 memset (&Crosshair
.AttachedPolygon
, 0, sizeof (PolygonType
));
1522 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
1528 /* create new point if it's the first one or if it's
1529 * different to the last one
1532 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1533 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1535 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1536 Crosshair
.AttachedLine
.Point2
.X
,
1537 Crosshair
.AttachedLine
.Point2
.Y
);
1539 /* copy the coordinates */
1540 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1541 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1550 case PASTEBUFFER_MODE
:
1552 TextType estr
[MAX_ELEMENTNAMES
];
1555 if (gui
->shift_is_pressed ())
1558 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1560 if (type
== ELEMENT_TYPE
)
1562 e
= (ElementType
*) ptr1
;
1567 memcpy (estr
, e
->Name
,
1568 MAX_ELEMENTNAMES
* sizeof (TextType
));
1569 for (i
= 0; i
< MAX_ELEMENTNAMES
; ++i
)
1570 estr
[i
].TextString
= estr
[i
].TextString
? strdup(estr
[i
].TextString
) : NULL
;
1575 if (CopyPastebufferToLayout (Note
.X
, Note
.Y
))
1576 SetChangedFlag (true);
1580 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1582 if (type
== ELEMENT_TYPE
&& ptr1
)
1585 e
= (ElementType
*) ptr1
;
1587 save_n
= NAME_INDEX (PCB
);
1589 for (i
= 0; i
< MAX_ELEMENTNAMES
; i
++)
1592 EraseElementName (e
);
1593 r_delete_entry (PCB
->Data
->name_tree
[i
],
1594 (BoxType
*) & (e
->Name
[i
]));
1595 memcpy (&(e
->Name
[i
]), &(estr
[i
]), sizeof (TextType
));
1596 e
->Name
[i
].Element
= e
;
1597 SetTextBoundingBox (&PCB
->Font
, &(e
->Name
[i
]));
1598 r_insert_entry (PCB
->Data
->name_tree
[i
],
1599 (BoxType
*) & (e
->Name
[i
]), 0);
1601 DrawElementName (e
);
1610 SearchScreen (Note
.X
, Note
.Y
, REMOVE_TYPES
, &ptr1
, &ptr2
,
1613 if (TEST_FLAG (LOCKFLAG
, (LineType
*) ptr2
))
1615 Message (_("Sorry, the object is locked\n"));
1618 if (type
== ELEMENT_TYPE
)
1620 RubberbandType
*ptr
;
1623 Crosshair
.AttachedObject
.RubberbandN
= 0;
1624 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
1625 ptr
= Crosshair
.AttachedObject
.Rubberband
;
1626 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
; i
++)
1629 EraseRat ((RatType
*) ptr
->Line
);
1630 if (TEST_FLAG (RUBBERENDFLAG
, ptr
->Line
))
1631 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
1632 ptr
->Line
, ptr
->Line
,
1635 TOGGLE_FLAG (RUBBERENDFLAG
, ptr
->Line
); /* only remove line once */
1639 RemoveObject (type
, ptr1
, ptr2
, ptr3
);
1640 IncrementUndoSerialNumber ();
1641 SetChangedFlag (true);
1646 RotateScreenObject (Note
.X
, Note
.Y
,
1647 gui
->shift_is_pressed ()? (SWAP_IDENT
?
1649 : (SWAP_IDENT
? 3 : 1));
1652 /* both are almost the same */
1655 switch (Crosshair
.AttachedObject
.State
)
1657 /* first notify, lookup object */
1660 int types
= (Settings
.Mode
== COPY_MODE
) ?
1661 COPY_TYPES
: MOVE_TYPES
;
1663 Crosshair
.AttachedObject
.Type
=
1664 SearchScreen (Note
.X
, Note
.Y
, types
,
1665 &Crosshair
.AttachedObject
.Ptr1
,
1666 &Crosshair
.AttachedObject
.Ptr2
,
1667 &Crosshair
.AttachedObject
.Ptr3
);
1668 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1670 if (Settings
.Mode
== MOVE_MODE
&&
1671 TEST_FLAG (LOCKFLAG
, (PinType
*)
1672 Crosshair
.AttachedObject
.Ptr2
))
1674 Message (_("Sorry, the object is locked\n"));
1675 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1678 AttachForCopy (Note
.X
, Note
.Y
);
1683 /* second notify, move or copy object */
1685 if (Settings
.Mode
== COPY_MODE
)
1686 CopyObject (Crosshair
.AttachedObject
.Type
,
1687 Crosshair
.AttachedObject
.Ptr1
,
1688 Crosshair
.AttachedObject
.Ptr2
,
1689 Crosshair
.AttachedObject
.Ptr3
,
1690 Note
.X
- Crosshair
.AttachedObject
.X
,
1691 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1694 MoveObjectAndRubberband (Crosshair
.AttachedObject
.Type
,
1695 Crosshair
.AttachedObject
.Ptr1
,
1696 Crosshair
.AttachedObject
.Ptr2
,
1697 Crosshair
.AttachedObject
.Ptr3
,
1698 Note
.X
- Crosshair
.AttachedObject
.X
,
1699 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1700 SetLocalRef (0, 0, false);
1702 SetChangedFlag (true);
1704 /* reset identifiers */
1705 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1706 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1711 /* insert a point into a polygon/line/... */
1712 case INSERTPOINT_MODE
:
1713 switch (Crosshair
.AttachedObject
.State
)
1715 /* first notify, lookup object */
1717 Crosshair
.AttachedObject
.Type
=
1718 SearchScreen (Note
.X
, Note
.Y
, INSERT_TYPES
,
1719 &Crosshair
.AttachedObject
.Ptr1
,
1720 &Crosshair
.AttachedObject
.Ptr2
,
1721 &Crosshair
.AttachedObject
.Ptr3
);
1723 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1725 if (TEST_FLAG (LOCKFLAG
, (PolygonType
*)
1726 Crosshair
.AttachedObject
.Ptr2
))
1728 Message (_("Sorry, the object is locked\n"));
1729 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1734 /* get starting point of nearest segment */
1735 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1738 (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
;
1740 GetLowestDistancePolygonPoint (fake
.poly
, Note
.X
,
1742 fake
.line
.Point1
= fake
.poly
->Points
[polyIndex
];
1743 fake
.line
.Point2
= fake
.poly
->Points
[
1744 prev_contour_point (fake
.poly
, polyIndex
)];
1745 Crosshair
.AttachedObject
.Ptr2
= &fake
.line
;
1748 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1749 InsertedPoint
= *AdjustInsertPoint ();
1754 /* second notify, insert new point into object */
1756 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1757 InsertPointIntoObject (POLYGON_TYPE
,
1758 Crosshair
.AttachedObject
.Ptr1
, fake
.poly
,
1760 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1762 InsertPointIntoObject (Crosshair
.AttachedObject
.Type
,
1763 Crosshair
.AttachedObject
.Ptr1
,
1764 Crosshair
.AttachedObject
.Ptr2
,
1766 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1767 SetChangedFlag (true);
1769 /* reset identifiers */
1770 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1771 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1779 /* --------------------------------------------------------------------------- */
1781 static const char atomic_syntax
[] = "Atomic(Save|Restore|Close|Block)";
1783 static const char atomic_help
[] = "Save or restore the undo serial number.";
1785 /* %start-doc actions Atomic
1787 This action allows making multiple-action bindings into an atomic
1788 operation that will be undone by a single Undo command. For example,
1789 to optimize rat lines, you'd delete the rats and re-add them. To
1790 group these into a single undo, you'd want the deletions and the
1791 additions to have the same undo serial number. So, you @code{Save},
1792 delete the rats, @code{Restore}, add the rats - using the same serial
1793 number as the deletes, then @code{Block}, which checks to see if the
1794 deletions or additions actually did anything. If not, the serial
1795 number is set to the saved number, as there's nothing to undo. If
1796 something did happen, the serial number is incremented so that these
1797 actions are counted as a single undo step.
1802 Saves the undo serial number.
1805 Returns it to the last saved number.
1808 Sets it to 1 greater than the last save.
1811 Does a Restore if there was nothing to undo, else does a Close.
1818 ActionAtomic (int argc
, char **argv
, Coord x
, Coord y
)
1823 switch (GetFunctionID (argv
[0]))
1826 SaveUndoSerialNumber ();
1829 RestoreUndoSerialNumber ();
1832 RestoreUndoSerialNumber ();
1833 IncrementUndoSerialNumber ();
1836 RestoreUndoSerialNumber ();
1838 IncrementUndoSerialNumber ();
1844 /* -------------------------------------------------------------------------- */
1846 static const char drc_syntax
[] = "DRC()";
1848 static const char drc_help
[] = "Invoke the DRC check.";
1850 /* %start-doc actions DRC
1852 Note that the design rule check uses the current board rule settings,
1853 not the current style settings.
1858 ActionDRCheck (int argc
, char **argv
, Coord x
, Coord y
)
1862 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1864 Message (_("%m+Rules are minspace %$mS, minoverlap %$mS "
1865 "minwidth %$mS, minsilk %$mS\n"
1866 "min drill %$mS, min annular ring %$mS\n"),
1867 Settings
.grid_unit
->allow
,
1868 PCB
->Bloat
, PCB
->Shrink
,
1869 PCB
->minWid
, PCB
->minSlk
,
1870 PCB
->minDrill
, PCB
->minRing
);
1873 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1876 Message (_("No DRC problems found.\n"));
1878 Message (_("Found %d design rule errors.\n"), count
);
1880 Message (_("Aborted DRC after %d design rule errors.\n"), -count
);
1885 /* -------------------------------------------------------------------------- */
1887 static const char dumplibrary_syntax
[] = "DumpLibrary()";
1889 static const char dumplibrary_help
[] =
1890 "Display the entire contents of the libraries.";
1892 /* %start-doc actions DumpLibrary
1898 ActionDumpLibrary (int argc
, char **argv
, Coord x
, Coord y
)
1902 printf ("**** Do not count on this format. It will change ****\n\n");
1903 printf ("MenuN = %d\n", Library
.MenuN
);
1904 printf ("MenuMax = %d\n", Library
.MenuMax
);
1905 for (i
= 0; i
< Library
.MenuN
; i
++)
1907 printf ("Library #%d:\n", i
);
1908 printf (" EntryN = %d\n", Library
.Menu
[i
].EntryN
);
1909 printf (" EntryMax = %d\n", Library
.Menu
[i
].EntryMax
);
1910 printf (" Name = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Name
));
1911 printf (" directory = \"%s\"\n",
1912 UNKNOWN (Library
.Menu
[i
].directory
));
1913 printf (" Style = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Style
));
1914 printf (" flag = %d\n", Library
.Menu
[i
].flag
);
1916 for (j
= 0; j
< Library
.Menu
[i
].EntryN
; j
++)
1918 printf (" #%4d: ", j
);
1919 if (Library
.Menu
[i
].Entry
[j
].Template
== (char *) -1)
1921 printf ("newlib: \"%s\"\n",
1922 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
));
1926 printf ("\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"\n",
1927 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
),
1928 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Template
),
1929 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Package
),
1930 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Value
),
1931 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Description
));
1939 /* -------------------------------------------------------------------------- */
1941 static const char flip_syntax
[] = "Flip(Object|Selected|SelectedElements)";
1943 static const char flip_help
[] =
1944 "Flip an element to the opposite side of the board.";
1946 /* %start-doc actions Flip
1948 Note that the location of the element will be symmetric about the
1949 cursor location; i.e. if the part you are pointing at will still be at
1950 the same spot once the element is on the other side. When flipping
1951 multiple elements, this retains their positions relative to each
1952 other, not their absolute positions on the board.
1957 ActionFlip (int argc
, char **argv
, Coord x
, Coord y
)
1959 char *function
= ARG (0);
1960 ElementType
*element
;
1966 switch (GetFunctionID (function
))
1969 if ((SearchScreen (x
, y
, ELEMENT_TYPE
,
1970 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
1972 element
= (ElementType
*) ptrtmp
;
1973 ChangeElementSide (element
, 2 * Crosshair
.Y
- PCB
->MaxHeight
);
1974 IncrementUndoSerialNumber ();
1979 case F_SelectedElements
:
1980 ChangeSelectedElementSide ();
1993 /* -------------------------------------------------------------------------- */
1995 static const char message_syntax
[] = "Message(message)";
1997 static const char message_help
[] = "Writes a message to the log window.";
1999 /* %start-doc actions Message
2001 This action displays a message to the log window. This action is primarily
2002 provided for use by other programs which may interface with PCB. If
2003 multiple arguments are given, each one is sent to the log window
2004 followed by a newline.
2009 ActionMessage (int argc
, char **argv
, Coord x
, Coord y
)
2016 for (i
= 0; i
< argc
; i
++)
2026 /* -------------------------------------------------------------------------- */
2028 static const char setthermal_syntax
[] =
2029 "SetThermal(Object|SelectedPins|SelectedVias|Selected, Style)";
2031 static const char setthermal_help
[] =
2032 "Set the thermal (on the current layer) of pins or vias to the given style.\n"
2033 "Style = 0 means no thermal.\n"
2034 "Style = 1 has diagonal fingers with sharp edges.\n"
2035 "Style = 2 has horizontal and vertical fingers with sharp edges.\n"
2036 "Style = 3 is a solid connection to the plane."
2037 "Style = 4 has diagonal fingers with rounded edges.\n"
2038 "Style = 5 has horizontal and vertical fingers with rounded edges.\n";
2040 /* %start-doc actions SetThermal
2042 This changes how/whether pins or vias connect to any rectangle or polygon
2043 on the current layer. The first argument can specify one object, or all
2044 selected pins, or all selected vias, or all selected pins and vias.
2045 The second argument specifies the style of connection.
2046 There are 5 possibilities:
2048 1 - 45 degree fingers with sharp edges,
2049 2 - horizontal & vertical fingers with sharp edges,
2050 3 - solid connection,
2051 4 - 45 degree fingers with rounded corners,
2052 5 - horizontal & vertical fingers with rounded corners.
2054 Pins and Vias may have thermals whether or not there is a polygon available
2055 to connect with. However, they will have no effect without the polygon.
2059 ActionSetThermal (int argc
, char **argv
, Coord x
, Coord y
)
2061 char *function
= ARG (0);
2062 char *style
= ARG (1);
2063 void *ptr1
, *ptr2
, *ptr3
;
2067 if (function
&& *function
&& style
&& *style
)
2071 kind
= GetValue (style
, NULL
, &absolute
);
2073 switch (GetFunctionID (function
))
2077 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGETHERMAL_TYPES
,
2078 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
2080 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, kind
);
2081 IncrementUndoSerialNumber ();
2085 case F_SelectedPins
:
2086 ChangeSelectedThermals (PIN_TYPE
, kind
);
2088 case F_SelectedVias
:
2089 ChangeSelectedThermals (VIA_TYPE
, kind
);
2092 case F_SelectedElements
:
2093 ChangeSelectedThermals (CHANGETHERMAL_TYPES
, kind
);
2108 /* ---------------------------------------------------------------------------
2109 * !!! no action routine !!!
2111 * event handler to set the cursor according to the X pointer position
2112 * called from inside main.c
2115 EventMoveCrosshair (int ev_x
, int ev_y
)
2117 #ifdef HAVE_LIBSTROKE
2120 StrokeBox
.X2
= ev_x
;
2121 StrokeBox
.Y2
= ev_y
;
2122 stroke_record (ev_x
, ev_y
);
2125 #endif /* HAVE_LIBSTROKE */
2126 if (MoveCrosshairAbsolute (ev_x
, ev_y
))
2128 /* update object position and cursor location */
2129 AdjustAttachedObjects ();
2130 notify_crosshair_change (true);
2134 /* --------------------------------------------------------------------------- */
2136 static const char setvalue_syntax
[] =
2137 "SetValue(Grid|Line|LineSize|Text|TextScale|ViaDrillingHole|Via|ViaSize, delta)";
2139 static const char setvalue_help
[] =
2140 "Change various board-wide values and sizes.";
2142 /* %start-doc actions SetValue
2146 @item ViaDrillingHole
2147 Changes the diameter of the drill for new vias.
2150 Sets the grid spacing.
2154 Changes the thickness of new lines.
2158 Changes the diameter of new vias.
2162 Changes the size of new text.
2169 ActionSetValue (int argc
, char **argv
, Coord x
, Coord y
)
2171 char *function
= ARG (0);
2172 char *val
= ARG (1);
2173 char *units
= ARG (2);
2174 bool absolute
; /* flag for 'absolute' value */
2179 if (function
&& val
)
2181 value
= GetValue (val
, units
, &absolute
);
2182 switch (GetFunctionID (function
))
2184 case F_ViaDrillingHole
:
2185 SetViaDrillingHole (absolute
? value
:
2186 value
+ Settings
.ViaDrillingHole
,
2188 hid_action ("RouteStylesChanged");
2193 SetGrid (value
, false);
2197 value
= val
[0] == '-' ? -Settings
.increments
->grid
2198 : Settings
.increments
->grid
;
2199 /* On the way down, short against the minimum
2200 * PCB drawing unit */
2201 if ((value
+ PCB
->Grid
) < 1)
2203 else if (PCB
->Grid
== 1)
2204 SetGrid (value
, false);
2206 SetGrid (value
+ PCB
->Grid
, false);
2212 if (!absolute
&& value
== 0)
2213 value
= val
[0] == '-' ? -Settings
.increments
->line
2214 : Settings
.increments
->line
;
2215 SetLineSize (absolute
? value
: value
+ Settings
.LineThickness
);
2216 hid_action ("RouteStylesChanged");
2221 SetViaSize (absolute
? value
: value
+ Settings
.ViaThickness
, false);
2222 hid_action ("RouteStylesChanged");
2227 text_scale
= value
/ (double)FONT_CAPHEIGHT
* 100.;
2229 text_scale
+= Settings
.TextScale
;
2230 SetTextScale (text_scale
);
2244 /* --------------------------------------------------------------------------- */
2246 static const char quit_syntax
[] = "Quit()";
2248 static const char quit_help
[] = "Quits the application after confirming.";
2250 /* %start-doc actions Quit
2252 If you have unsaved changes, you will be prompted to confirm (or
2253 save) before quitting.
2258 ActionQuit (int argc
, char **argv
, Coord x
, Coord y
)
2260 char *force
= ARG (0);
2261 if (force
&& strcasecmp (force
, "force") == 0)
2266 if (!PCB
->Changed
|| gui
->close_confirm_dialog () == HID_CLOSE_CONFIRM_OK
)
2271 /* --------------------------------------------------------------------------- */
2273 static const char connection_syntax
[] =
2274 "Connection(Find|ResetLinesAndPolygons|ResetPinsAndVias|Reset)";
2276 static const char connection_help
[] =
2277 "Searches connections of the object at the cursor position.";
2279 /* %start-doc actions Connection
2281 Connections found with this action will be highlighted in the
2282 ``connected-color'' color and will have the ``found'' flag set.
2287 The net under the cursor is ``found''.
2289 @item ResetLinesAndPolygons
2290 Any ``found'' lines and polygons are marked ``not found''.
2292 @item ResetPinsAndVias
2293 Any ``found'' pins and vias are marked ``not found''.
2296 All ``found'' objects are marked ``not found''.
2303 ActionConnection (int argc
, char **argv
, Coord x
, Coord y
)
2305 char *function
= ARG (0);
2308 switch (GetFunctionID (function
))
2312 gui
->get_coords (_("Click on a connection"), &x
, &y
);
2313 LookupConnection (x
, y
, true, 1, FOUNDFLAG
);
2317 case F_ResetLinesAndPolygons
:
2318 if (ResetFoundLinesAndPolygons (true))
2320 IncrementUndoSerialNumber ();
2325 case F_ResetPinsViasAndPads
:
2326 if (ResetFoundPinsViasAndPads (true))
2328 IncrementUndoSerialNumber ();
2334 if (ResetConnections (true))
2336 IncrementUndoSerialNumber ();
2347 /* --------------------------------------------------------------------------- */
2349 static const char disperseelements_syntax
[] =
2350 "DisperseElements(All|Selected)";
2352 static const char disperseelements_help
[] = "Disperses elements.";
2354 /* %start-doc actions DisperseElements
2356 Normally this is used when starting a board, by selecting all elements
2357 and then dispersing them. This scatters the elements around the board
2358 so that you can pick individual ones, rather than have all the
2359 elements at the same 0,0 coordinate and thus impossible to choose
2364 #define GAP MIL_TO_COORD(100)
2367 ActionDisperseElements (int argc
, char **argv
, Coord x
, Coord y
)
2369 char *function
= ARG (0);
2374 int all
= 0, bad
= 0;
2376 if (!function
|| !*function
)
2382 switch (GetFunctionID (function
))
2399 AFAIL (disperseelements
);
2403 ELEMENT_LOOP (PCB
->Data
);
2406 * If we want to disperse selected elements, maybe we need smarter
2407 * code here to avoid putting components on top of others which
2408 * are not selected. For now, I'm assuming that this is typically
2409 * going to be used either with a brand new design or a scratch
2410 * design holding some new components
2412 if (!TEST_FLAG (LOCKFLAG
, element
) && (all
|| TEST_FLAG (SELECTEDFLAG
, element
)))
2415 /* figure out how much to move the element */
2416 dx
= minx
- element
->BoundingBox
.X1
;
2418 /* snap to the grid */
2419 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2422 * and add one grid size so we make sure we always space by GAP or
2427 /* Figure out if this row has room. If not, start a new row */
2428 if (GAP
+ element
->BoundingBox
.X2
+ dx
> PCB
->MaxWidth
)
2434 /* figure out how much to move the element */
2435 dx
= minx
- element
->BoundingBox
.X1
;
2436 dy
= miny
- element
->BoundingBox
.Y1
;
2438 /* snap to the grid */
2439 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2441 dy
-= (element
->MarkY
+ dy
) % PCB
->Grid
;
2444 /* move the element */
2445 MoveElementLowLevel (PCB
->Data
, element
, dx
, dy
);
2447 /* and add to the undo list so we can undo this operation */
2448 AddObjectToMoveUndoList (ELEMENT_TYPE
, NULL
, NULL
, element
, dx
, dy
);
2450 /* keep track of how tall this row is */
2451 minx
+= element
->BoundingBox
.X2
- element
->BoundingBox
.X1
+ GAP
;
2452 if (maxy
< element
->BoundingBox
.Y2
)
2454 maxy
= element
->BoundingBox
.Y2
;
2461 /* done with our action so increment the undo # */
2462 IncrementUndoSerialNumber ();
2465 SetChangedFlag (true);
2472 /* --------------------------------------------------------------------------- */
2474 static const char display_syntax
[] =
2475 "Display(NameOnPCB|Description|Value)\n"
2476 "Display(Grid|Redraw)\n"
2477 "Display(CycleClip|CycleCrosshair|Toggle45Degree|ToggleStartDirection)\n"
2478 "Display(ToggleGrid|ToggleRubberBandMode|ToggleUniqueNames)\n"
2479 "Display(ToggleMask|ToggleName|ToggleClearLine|ToggleFullPoly|ToggleSnapPin)\n"
2480 "Display(ToggleThindraw|ToggleThindrawPoly|ToggleOrthoMove|ToggleLocalRef)\n"
2481 "Display(ToggleCheckPlanes|ToggleShowDRC|ToggleAutoDRC)\n"
2482 "Display(ToggleLiveRoute|LockNames|OnlyNames)\n"
2483 "Display(Pinout|PinOrPadName)";
2485 static const char display_help
[] = "Several display-related actions.";
2487 /* %start-doc actions Display
2494 Specify whether all elements show their name, description, or value.
2497 Redraw the whole board.
2499 @item Toggle45Degree
2500 When clear, lines can be drawn at any angle. When set, lines are
2501 restricted to multiples of 45 degrees and requested lines may be
2502 broken up according to the clip setting.
2505 Changes the way lines are restricted to 45 degree increments. The
2506 various settings are: straight only, orthogonal then angled, and angled
2507 then orthogonal. If AllDirections is set, this action disables it.
2509 @item CycleCrosshair
2510 Changes crosshair drawing. Crosshair may accept form of 4-ray,
2511 8-ray and 12-ray cross.
2513 @item ToggleRubberBandMode
2514 If set, moving an object moves all the lines attached to it too.
2516 @item ToggleStartDirection
2517 If set, each time you set a point in a line, the Clip toggles between
2518 orth-angle and angle-ortho.
2520 @item ToggleUniqueNames
2521 If set, you will not be permitted to change the name of an element to
2522 match that of another element.
2525 If set, pin centers and pad end points are treated as additional grid
2526 points that the cursor can snap to.
2528 @item ToggleLocalRef
2529 If set, the mark is automatically set to the beginning of any move, so
2530 you can see the relative distance you've moved.
2532 @item ToggleThindraw
2533 If set, objects on the screen are drawn as outlines (lines are drawn
2534 as center-lines). This lets you see line endpoints hidden under pins,
2537 @item ToggleThindrawPoly
2538 If set, polygons on the screen are drawn as outlines.
2541 If set, pending objects (i.e. lines you're in the process of drawing)
2542 will be drawn with an outline showing how far away from other copper
2545 @item ToggleLiveRoute
2546 If set, the progress of the autorouter will be visible on the screen.
2549 If set, you will not be permitted to make connections which violate
2550 the current DRC and netlist settings.
2552 @item ToggleCheckPlanes
2553 If set, lines and arcs aren't drawn, which usually leaves just the
2554 polygons. If you also disable all but the layer you're interested in,
2555 this allows you to check for isolated regions.
2557 @item ToggleOrthoMove
2558 If set, the crosshair is only allowed to move orthogonally from its
2559 previous position. I.e. you can move an element or line up, down,
2560 left, or right, but not up+left or down+right.
2563 Selects whether the pinouts show the pin names or the pin numbers.
2565 @item ToggleLockNames
2566 If set, text will ignore left mouse clicks and actions that work on
2567 objects under the mouse. You can still select text with a lasso (left
2568 mouse drag) and perform actions on the selection.
2570 @item ToggleOnlyNames
2571 If set, only text will be sensitive for mouse clicks and actions that
2572 work on objects under the mouse. You can still select other objects
2573 with a lasso (left mouse drag) and perform actions on the selection.
2576 Turns the solder mask on or off.
2578 @item ToggleClearLine
2579 When set, the clear-line flag causes new lines and arcs to have their
2580 ``clear polygons'' flag set, so they won't be electrically connected
2581 to any polygons they overlap.
2583 @item ToggleFullPoly
2584 When set, the full-poly flag causes new polygons to have their
2585 ``full polygon'' flag set, so all parts of them will be displayed
2586 instead of only the biggest one.
2589 Resets the origin of the current grid to be wherever the mouse pointer
2590 is (not where the crosshair currently is). If you provide two numbers
2591 after this, the origin is set to that coordinate.
2594 Toggles whether the grid is displayed or not.
2597 Causes the pinout of the element indicated by the cursor to be
2598 displayed, usually in a separate window.
2601 Toggles whether the names of pins, pads, or (yes) vias will be
2602 displayed. If the cursor is over an element, all of its pins and pads
2609 static enum crosshair_shape
2610 CrosshairShapeIncrement (enum crosshair_shape shape
)
2614 case Basic_Crosshair_Shape
:
2615 shape
= Union_Jack_Crosshair_Shape
;
2617 case Union_Jack_Crosshair_Shape
:
2618 shape
= Dozen_Crosshair_Shape
;
2620 case Dozen_Crosshair_Shape
:
2621 shape
= Crosshair_Shapes_Number
;
2623 case Crosshair_Shapes_Number
:
2624 shape
= Basic_Crosshair_Shape
;
2631 ActionDisplay (int argc
, char **argv
, Coord childX
, Coord childY
)
2633 char *function
, *str_dir
;
2640 if (function
&& (!str_dir
|| !*str_dir
))
2642 switch (id
= GetFunctionID (function
))
2646 case F_ClearAndRedraw
:
2651 /* change the displayed name of elements */
2655 ELEMENT_LOOP (PCB
->Data
);
2657 EraseElementName (element
);
2660 CLEAR_FLAG (DESCRIPTIONFLAG
| NAMEONPCBFLAG
, PCB
);
2666 SET_FLAG (NAMEONPCBFLAG
, PCB
);
2669 SET_FLAG (DESCRIPTIONFLAG
, PCB
);
2672 ELEMENT_LOOP (PCB
->Data
);
2674 DrawElementName (element
);
2680 /* toggle line-adjust flag */
2681 case F_ToggleAllDirections
:
2682 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2683 AdjustAttachedObjects ();
2687 notify_crosshair_change (false);
2688 if (TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
2690 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2694 PCB
->Clipping
= (PCB
->Clipping
+ 1) % 3;
2695 AdjustAttachedObjects ();
2696 notify_crosshair_change (true);
2699 case F_CycleCrosshair
:
2700 notify_crosshair_change (false);
2701 Crosshair
.shape
= CrosshairShapeIncrement(Crosshair
.shape
);
2702 if (Crosshair_Shapes_Number
== Crosshair
.shape
)
2703 Crosshair
.shape
= Basic_Crosshair_Shape
;
2704 notify_crosshair_change (true);
2707 case F_ToggleRubberBandMode
:
2708 notify_crosshair_change (false);
2709 TOGGLE_FLAG (RUBBERBANDFLAG
, PCB
);
2710 notify_crosshair_change (true);
2713 case F_ToggleStartDirection
:
2714 notify_crosshair_change (false);
2715 TOGGLE_FLAG (SWAPSTARTDIRFLAG
, PCB
);
2716 notify_crosshair_change (true);
2719 case F_ToggleUniqueNames
:
2720 TOGGLE_FLAG (UNIQUENAMEFLAG
, PCB
);
2723 case F_ToggleSnapPin
:
2724 notify_crosshair_change (false);
2725 TOGGLE_FLAG (SNAPPINFLAG
, PCB
);
2726 notify_crosshair_change (true);
2729 case F_ToggleLocalRef
:
2730 TOGGLE_FLAG (LOCALREFFLAG
, PCB
);
2733 case F_ToggleThindraw
:
2734 TOGGLE_FLAG (THINDRAWFLAG
, PCB
);
2738 case F_ToggleThindrawPoly
:
2739 TOGGLE_FLAG (THINDRAWPOLYFLAG
, PCB
);
2743 case F_ToggleLockNames
:
2744 TOGGLE_FLAG (LOCKNAMESFLAG
, PCB
);
2745 CLEAR_FLAG (ONLYNAMESFLAG
, PCB
);
2748 case F_ToggleOnlyNames
:
2749 TOGGLE_FLAG (ONLYNAMESFLAG
, PCB
);
2750 CLEAR_FLAG (LOCKNAMESFLAG
, PCB
);
2753 case F_ToggleHideNames
:
2754 TOGGLE_FLAG (HIDENAMESFLAG
, PCB
);
2758 case F_ToggleShowDRC
:
2759 TOGGLE_FLAG (SHOWDRCFLAG
, PCB
);
2762 case F_ToggleLiveRoute
:
2763 TOGGLE_FLAG (LIVEROUTEFLAG
, PCB
);
2766 case F_ToggleAutoDRC
:
2767 notify_crosshair_change (false);
2768 TOGGLE_FLAG (AUTODRCFLAG
, PCB
);
2769 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
2771 if (ResetConnections (true))
2773 IncrementUndoSerialNumber ();
2776 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
2777 LookupConnection (Crosshair
.AttachedLine
.Point1
.X
,
2778 Crosshair
.AttachedLine
.Point1
.Y
, true, 1,
2781 notify_crosshair_change (true);
2784 case F_ToggleCheckPlanes
:
2785 TOGGLE_FLAG (CHECKPLANESFLAG
, PCB
);
2789 case F_ToggleOrthoMove
:
2790 TOGGLE_FLAG (ORTHOMOVEFLAG
, PCB
);
2794 TOGGLE_FLAG (SHOWNUMBERFLAG
, PCB
);
2799 TOGGLE_FLAG (SHOWMASKFLAG
, PCB
);
2803 case F_ToggleClearLine
:
2804 TOGGLE_FLAG (CLEARNEWFLAG
, PCB
);
2807 case F_ToggleFullPoly
:
2808 TOGGLE_FLAG (NEWFULLPOLYFLAG
, PCB
);
2811 /* shift grid alignment */
2814 Coord oldGrid
= PCB
->Grid
;
2817 if (MoveCrosshairAbsolute (Crosshair
.X
, Crosshair
.Y
))
2818 notify_crosshair_change (true); /* first notify was in MoveCrosshairAbs */
2819 SetGrid (oldGrid
, true);
2823 /* toggle displaying of the grid */
2825 Settings
.DrawGrid
= !Settings
.DrawGrid
;
2829 /* display the pinout of an element */
2832 ElementType
*element
;
2836 gui
->get_coords (_("Click on an element"), &x
, &y
);
2838 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
2839 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
2841 element
= (ElementType
*) ptrtmp
;
2842 gui
->show_item (element
);
2847 /* toggle displaying of pin/pad/via names */
2848 case F_PinOrPadName
:
2850 void *ptr1
, *ptr2
, *ptr3
;
2852 switch (SearchScreen (Crosshair
.X
, Crosshair
.Y
,
2853 ELEMENT_TYPE
| PIN_TYPE
| PAD_TYPE
|
2854 VIA_TYPE
, (void **) &ptr1
, (void **) &ptr2
,
2858 PIN_LOOP ((ElementType
*) ptr1
);
2860 if (TEST_FLAG (DISPLAYNAMEFLAG
, pin
))
2864 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, pin
, pin
);
2865 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pin
);
2868 PAD_LOOP ((ElementType
*) ptr1
);
2870 if (TEST_FLAG (DISPLAYNAMEFLAG
, pad
))
2874 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, pad
, pad
);
2875 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pad
);
2878 SetChangedFlag (true);
2879 IncrementUndoSerialNumber ();
2884 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
))
2885 ErasePinName ((PinType
*) ptr2
);
2887 DrawPinName ((PinType
*) ptr2
);
2888 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, ptr2
, ptr3
);
2889 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
);
2890 SetChangedFlag (true);
2891 IncrementUndoSerialNumber ();
2896 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PadType
*) ptr2
))
2897 ErasePadName ((PadType
*) ptr2
);
2899 DrawPadName ((PadType
*) ptr2
);
2900 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, ptr2
, ptr3
);
2901 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PadType
*) ptr2
);
2902 SetChangedFlag (true);
2903 IncrementUndoSerialNumber ();
2907 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
))
2908 EraseViaName ((PinType
*) ptr2
);
2910 DrawViaName ((PinType
*) ptr2
);
2911 AddObjectToFlagUndoList (VIA_TYPE
, ptr1
, ptr2
, ptr3
);
2912 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
);
2913 SetChangedFlag (true);
2914 IncrementUndoSerialNumber ();
2924 else if (function
&& str_dir
)
2926 switch (GetFunctionID (function
))
2931 PCB
->GridOffsetX
= GetValue (argv
[1], NULL
, NULL
);
2932 PCB
->GridOffsetY
= GetValue (argv
[2], NULL
, NULL
);
2933 if (Settings
.DrawGrid
)
2950 /* --------------------------------------------------------------------------- */
2952 static const char mode_syntax
[] =
2953 "Mode(Arc|Arrow|Copy|InsertPoint|Line|Lock|Move|None|PasteBuffer)\n"
2954 "Mode(Polygon|Rectangle|Remove|Rotate|Text|Thermal|Via)\n"
2955 "Mode(Notify|Release|Cancel|Stroke)\n"
2956 "Mode(Save|Restore)";
2958 static const char mode_help
[] = "Change or use the tool mode.";
2960 /* %start-doc actions Mode
2980 Select the indicated tool.
2983 Called when you press the mouse button, or move the mouse.
2986 Called when you release the mouse button.
2989 Cancels any pending tool activity, allowing you to restart elsewhere.
2990 For example, this allows you to start a new line rather than attach a
2991 line to the previous line.
2994 Similar to Cancel but calling this action a second time will return
2998 If your @code{pcb} was built with libstroke, this invokes the stroke
2999 input method. If not, this will restart a drawing mode if you were
3000 drawing, else it will select objects.
3003 Remembers the current tool.
3006 Restores the tool to the last saved tool.
3013 ActionMode (int argc
, char **argv
, Coord x
, Coord y
)
3015 char *function
= ARG (0);
3019 Note
.X
= Crosshair
.X
;
3020 Note
.Y
= Crosshair
.Y
;
3021 notify_crosshair_change (false);
3022 switch (GetFunctionID (function
))
3028 SetMode (ARROW_MODE
);
3031 SetMode (COPY_MODE
);
3034 SetMode (INSERTPOINT_MODE
);
3037 SetMode (LINE_MODE
);
3040 SetMode (LOCK_MODE
);
3043 SetMode (MOVE_MODE
);
3050 int saved_mode
= Settings
.Mode
;
3052 SetMode (saved_mode
);
3057 switch (Settings
.Mode
)
3060 case PASTEBUFFER_MODE
:
3066 case INSERTPOINT_MODE
:
3067 case RUBBERBANDMOVE_MODE
:
3071 SetMode (ARROW_MODE
);
3075 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3076 SetMode (ARROW_MODE
);
3080 SetMode (LINE_MODE
);
3084 case RECTANGLE_MODE
:
3085 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3086 SetMode (ARROW_MODE
);
3090 SetMode (RECTANGLE_MODE
);
3095 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3096 SetMode (ARROW_MODE
);
3100 SetMode (POLYGON_MODE
);
3104 case POLYGONHOLE_MODE
:
3105 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3106 SetMode (ARROW_MODE
);
3110 SetMode (POLYGONHOLE_MODE
);
3115 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3116 SetMode (ARROW_MODE
);
3137 SetMode (PASTEBUFFER_MODE
);
3140 SetMode (POLYGON_MODE
);
3143 SetMode (POLYGONHOLE_MODE
);
3145 #ifndef HAVE_LIBSTROKE
3158 SetMode (REMOVE_MODE
);
3161 SetMode (RECTANGLE_MODE
);
3164 SetMode (ROTATE_MODE
);
3167 #ifdef HAVE_LIBSTROKE
3169 StrokeBox
.X1
= Crosshair
.X
;
3170 StrokeBox
.Y1
= Crosshair
.Y
;
3173 /* Handle middle mouse button restarts of drawing mode. If not in
3174 | a drawing mode, middle mouse button will select objects.
3176 if (Settings
.Mode
== LINE_MODE
3177 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3179 SetMode (LINE_MODE
);
3181 else if (Settings
.Mode
== ARC_MODE
3182 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3184 else if (Settings
.Mode
== RECTANGLE_MODE
3185 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3186 SetMode (RECTANGLE_MODE
);
3187 else if (Settings
.Mode
== POLYGON_MODE
3188 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3189 SetMode (POLYGON_MODE
);
3194 SetMode (ARROW_MODE
);
3200 SetMode (TEXT_MODE
);
3203 SetMode (THERMAL_MODE
);
3209 case F_Restore
: /* restore the last saved mode */
3213 case F_Save
: /* save currently selected mode */
3217 notify_crosshair_change (true);
3224 /* --------------------------------------------------------------------------- */
3226 static const char removeselected_syntax
[] = "RemoveSelected()";
3228 static const char removeselected_help
[] = "Removes any selected objects.";
3230 /* %start-doc actions RemoveSelected
3235 ActionRemoveSelected (int argc
, char **argv
, Coord x
, Coord y
)
3237 if (RemoveSelected ())
3238 SetChangedFlag (true);
3242 /* --------------------------------------------------------------------------- */
3244 static const char renumber_syntax
[] = "Renumber()\n"
3245 "Renumber(filename)";
3247 static const char renumber_help
[] =
3248 "Renumber all elements. The changes will be recorded to filename\n"
3249 "for use in backannotating these changes to the schematic.";
3251 /* %start-doc actions Renumber
3256 ActionRenumber (int argc
, char **argv
, Coord x
, Coord y
)
3258 bool changed
= false;
3259 ElementType
**element_list
;
3260 ElementType
**locked_element_list
;
3261 unsigned int i
, j
, k
, cnt
, lock_cnt
;
3267 static char * default_file
= NULL
;
3268 size_t cnt_list_sz
= 100;
3274 char **was
, **is
, *pin
;
3275 unsigned int c_cnt
= 0;
3282 * We deal with the case where name already exists in this
3283 * function so the GUI doesn't need to deal with it
3285 name
= gui
->fileselect (_("Save Renumber Annotation File As ..."),
3286 _("Choose a file to record the renumbering to.\n"
3287 "This file may be used to back annotate the\n"
3288 "change to the schematics.\n"),
3289 default_file
, ".eco", "eco",
3299 free (default_file
);
3300 default_file
= NULL
;
3305 default_file
= strdup (name
);
3308 if ((out
= fopen (name
, "r")))
3311 if (!gui
->confirm_dialog (_("File exists! Ok to overwrite?"), 0))
3313 if (free_name
&& name
)
3319 if ((out
= fopen (name
, "w")) == NULL
)
3321 Message (_("Could not open %s\n"), name
);
3322 if (free_name
&& name
)
3327 if (free_name
&& name
)
3330 fprintf (out
, "*COMMENT* PCB Annotation File\n");
3331 fprintf (out
, "*FILEVERSION* 20061031\n");
3334 * Make a first pass through all of the elements and sort them out
3335 * by location on the board. While here we also collect a list of
3338 * We'll actually renumber things in the 2nd pass.
3340 element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementType
*));
3341 locked_element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementType
*));
3342 was
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3343 is
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3344 if (element_list
== NULL
|| locked_element_list
== NULL
|| was
== NULL
3347 fprintf (stderr
, "calloc() failed in %s\n", __FUNCTION__
);
3354 ELEMENT_LOOP (PCB
->Data
);
3356 if (TEST_FLAG (LOCKFLAG
, element
->Name
) || TEST_FLAG (LOCKFLAG
, element
))
3359 * add to the list of locked elements which we won't try to
3360 * renumber and whose reference designators are now reserved.
3363 "*WARN* Element \"%s\" at %$md is locked and will not be renumbered.\n",
3364 UNKNOWN (NAMEONPCB_NAME (element
)), element
->MarkX
, element
->MarkY
);
3365 locked_element_list
[lock_cnt
] = element
;
3371 /* count of devices which will be renumbered */
3374 /* search for correct position in the list */
3376 while (element_list
[i
] && element
->MarkY
> element_list
[i
]->MarkY
)
3380 * We have found the position where we have the first element that
3381 * has the same Y value or a lower Y value. Now move forward if
3382 * needed through the X values
3384 while (element_list
[i
]
3385 && element
->MarkY
== element_list
[i
]->MarkY
3386 && element
->MarkX
> element_list
[i
]->MarkX
)
3389 for (j
= cnt
- 1; j
> i
; j
--)
3391 element_list
[j
] = element_list
[j
- 1];
3393 element_list
[i
] = element
;
3400 * Now that the elements are sorted by board position, we go through
3401 * and renumber them.
3405 * turn off the flag which requires unique names so it doesn't get
3406 * in our way. When we're done with the renumber we will have unique
3409 unique
= TEST_FLAG (UNIQUENAMEFLAG
, PCB
);
3410 CLEAR_FLAG (UNIQUENAMEFLAG
, PCB
);
3412 cnt_list
= (struct _cnt_list
*)calloc (cnt_list_sz
, sizeof (struct _cnt_list
));
3413 for (i
= 0; i
< cnt
; i
++)
3415 /* If there is no refdes, maybe just spit out a warning */
3416 if (NAMEONPCB_NAME (element_list
[i
]))
3418 /* figure out the prefix */
3419 tmps
= strdup (NAMEONPCB_NAME (element_list
[i
]));
3421 while (tmps
[j
] && (tmps
[j
] < '0' || tmps
[j
] > '9')
3426 /* check the counter for this prefix */
3428 cnt_list
[j
].name
&& (strcmp (cnt_list
[j
].name
, tmps
) != 0)
3429 && j
< cnt_list_sz
; j
++);
3431 /* grow the list if needed */
3432 if (j
== cnt_list_sz
)
3435 cnt_list
= (struct _cnt_list
*)realloc (cnt_list
, cnt_list_sz
);
3436 if (cnt_list
== NULL
)
3438 fprintf (stderr
, "realloc failed() in %s\n", __FUNCTION__
);
3441 /* zero out the memory that we added */
3442 for (tmpi
= j
; tmpi
< cnt_list_sz
; tmpi
++)
3444 cnt_list
[tmpi
].name
= NULL
;
3445 cnt_list
[tmpi
].cnt
= 0;
3450 * start a new counter if we don't have a counter for this
3453 if (!cnt_list
[j
].name
)
3455 cnt_list
[j
].name
= strdup (tmps
);
3456 cnt_list
[j
].cnt
= 0;
3460 * check to see if the new refdes is already used by a
3469 /* space for the prefix plus 1 digit plus the '\0' */
3470 sz
= strlen (cnt_list
[j
].name
) + 2;
3472 /* and 1 more per extra digit needed to hold the number */
3473 tmpi
= cnt_list
[j
].cnt
;
3479 tmps
= (char *)malloc (sz
* sizeof (char));
3480 sprintf (tmps
, "%s%d", cnt_list
[j
].name
, cnt_list
[j
].cnt
);
3483 * now compare to the list of reserved (by locked
3486 for (k
= 0; k
< lock_cnt
; k
++)
3489 (UNKNOWN (NAMEONPCB_NAME (locked_element_list
[k
])),
3500 if (strcmp (tmps
, NAMEONPCB_NAME (element_list
[i
])) != 0)
3502 fprintf (out
, "*RENAME* \"%s\" \"%s\"\n",
3503 NAMEONPCB_NAME (element_list
[i
]), tmps
);
3505 /* add this rename to our table of renames so we can update the netlist */
3506 was
[c_cnt
] = strdup (NAMEONPCB_NAME (element_list
[i
]));
3507 is
[c_cnt
] = strdup (tmps
);
3510 AddObjectToChangeNameUndoList (ELEMENT_TYPE
, NULL
, NULL
,
3512 NAMEONPCB_NAME (element_list
3515 ChangeObjectName (ELEMENT_TYPE
, element_list
[i
], NULL
, NULL
,
3519 /* we don't free tmps in this case because it is used */
3526 pcb_fprintf (out
, "*WARN* Element at %$md has no name.\n",
3527 element_list
[i
]->MarkX
, element_list
[i
]->MarkY
);
3534 /* restore the unique flag setting */
3536 SET_FLAG (UNIQUENAMEFLAG
, PCB
);
3541 /* update the netlist */
3542 AddNetlistLibToUndoList (&(PCB
->NetlistLib
));
3544 /* iterate over each net */
3545 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
3548 /* iterate over each pin on the net */
3549 for (j
= 0; j
< PCB
->NetlistLib
.Menu
[i
].EntryN
; j
++)
3552 /* figure out the pin number part from strings like U3-21 */
3553 tmps
= strdup (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3554 for (k
= 0; tmps
[k
] && tmps
[k
] != '-'; k
++);
3558 /* iterate over the list of changed reference designators */
3559 for (k
= 0; k
< c_cnt
; k
++)
3562 * if the pin needs to change, change it and quit
3563 * searching in the list.
3565 if (strcmp (tmps
, was
[k
]) == 0)
3567 free (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3568 PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
=
3569 (char *)malloc ((strlen (is
[k
]) + strlen (pin
) +
3570 2) * sizeof (char));
3571 sprintf (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
,
3572 "%s-%s", is
[k
], pin
);
3580 for (k
= 0; k
< c_cnt
; k
++)
3587 IncrementUndoSerialNumber ();
3588 SetChangedFlag (true);
3591 free (locked_element_list
);
3592 free (element_list
);
3598 /* --------------------------------------------------------------------------- */
3600 static const char ripup_syntax
[] = "RipUp(All|Selected|Element)";
3602 static const char ripup_help
[] =
3603 "Ripup auto-routed tracks, or convert an element to parts.";
3605 /* %start-doc actions RipUp
3610 Removes all lines and vias which were created by the autorouter.
3613 Removes all selected lines and vias which were created by the
3617 Converts the element under the cursor to parts (vias and lines). Note
3618 that this uses the highest numbered paste buffer.
3625 ActionRipUp (int argc
, char **argv
, Coord x
, Coord y
)
3627 char *function
= ARG (0);
3628 bool changed
= false;
3632 switch (GetFunctionID (function
))
3635 ALLLINE_LOOP (PCB
->Data
);
3637 if (TEST_FLAG (AUTOFLAG
, line
) && !TEST_FLAG (LOCKFLAG
, line
))
3639 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3644 ALLARC_LOOP (PCB
->Data
);
3646 if (TEST_FLAG (AUTOFLAG
, arc
) && !TEST_FLAG (LOCKFLAG
, arc
))
3648 RemoveObject (ARC_TYPE
, layer
, arc
, arc
);
3653 VIA_LOOP (PCB
->Data
);
3655 if (TEST_FLAG (AUTOFLAG
, via
) && !TEST_FLAG (LOCKFLAG
, via
))
3657 RemoveObject (VIA_TYPE
, via
, via
, via
);
3665 IncrementUndoSerialNumber ();
3666 SetChangedFlag (true);
3670 VISIBLELINE_LOOP (PCB
->Data
);
3672 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, line
)
3673 && !TEST_FLAG (LOCKFLAG
, line
))
3675 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3681 VIA_LOOP (PCB
->Data
);
3683 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, via
)
3684 && !TEST_FLAG (LOCKFLAG
, via
))
3686 RemoveObject (VIA_TYPE
, via
, via
, via
);
3693 IncrementUndoSerialNumber ();
3694 SetChangedFlag (true);
3699 void *ptr1
, *ptr2
, *ptr3
;
3701 if (SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
3702 &ptr1
, &ptr2
, &ptr3
) != NO_TYPE
)
3704 Note
.Buffer
= Settings
.BufferNumber
;
3705 SetBufferNumber (MAX_BUFFER
- 1);
3706 ClearBuffer (PASTEBUFFER
);
3707 CopyObjectToBuffer (PASTEBUFFER
->Data
, PCB
->Data
,
3708 ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3709 SmashBufferElement (PASTEBUFFER
);
3712 SaveUndoSerialNumber ();
3713 EraseObject (ELEMENT_TYPE
, ptr1
, ptr1
);
3714 MoveObjectToRemoveUndoList (ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3715 RestoreUndoSerialNumber ();
3716 CopyPastebufferToLayout (0, 0);
3717 SetBufferNumber (Note
.Buffer
);
3718 SetChangedFlag (true);
3727 /* --------------------------------------------------------------------------- */
3729 static const char addrats_syntax
[] = "AddRats(AllRats|SelectedRats|Close)";
3731 static const char addrats_help
[] = "Add one or more rat lines to the board.";
3733 /* %start-doc actions AddRats
3738 Create rat lines for all loaded nets that aren't already connected on
3742 Similarly, but only add rat lines for nets connected to selected pins
3746 Selects the shortest unselected rat on the board.
3753 ActionAddRats (int argc
, char **argv
, Coord x
, Coord y
)
3755 char *function
= ARG (0);
3761 if (Settings
.RatWarn
)
3763 switch (GetFunctionID (function
))
3766 if (AddAllRats (false, NULL
))
3767 SetChangedFlag (true);
3769 case F_SelectedRats
:
3771 if (AddAllRats (true, NULL
))
3772 SetChangedFlag (true);
3775 small
= SQUARE (MAX_COORD
);
3777 RAT_LOOP (PCB
->Data
);
3779 if (TEST_FLAG (SELECTEDFLAG
, line
))
3781 len
= SQUARE (line
->Point1
.X
- line
->Point2
.X
) +
3782 SQUARE (line
->Point1
.Y
- line
->Point2
.Y
);
3792 AddObjectToFlagUndoList (RATLINE_TYPE
, shorty
, shorty
, shorty
);
3793 SET_FLAG (SELECTEDFLAG
, shorty
);
3796 CenterDisplay ((shorty
->Point2
.X
+ shorty
->Point1
.X
) / 2,
3797 (shorty
->Point2
.Y
+ shorty
->Point1
.Y
) / 2);
3805 /* --------------------------------------------------------------------------- */
3807 static const char delete_syntax
[] =
3808 "Delete(Object|Selected)\n"
3809 "Delete(AllRats|SelectedRats)";
3811 static const char delete_help
[] = "Delete stuff.";
3813 /* %start-doc actions Delete
3818 ActionDelete (int argc
, char **argv
, Coord x
, Coord y
)
3820 char *function
= ARG (0);
3821 int id
= GetFunctionID (function
);
3823 Note
.X
= Crosshair
.X
;
3824 Note
.Y
= Crosshair
.Y
;
3826 if (id
== -1) /* no arg */
3828 if (RemoveSelected() == false)
3836 SetMode(REMOVE_MODE
);
3844 if (DeleteRats (false))
3845 SetChangedFlag (true);
3847 case F_SelectedRats
:
3848 if (DeleteRats (true))
3849 SetChangedFlag (true);
3856 /* --------------------------------------------------------------------------- */
3858 static const char deleterats_syntax
[] =
3859 "DeleteRats(AllRats|Selected|SelectedRats)";
3861 static const char deleterats_help
[] = "Delete rat lines.";
3863 /* %start-doc actions DeleteRats
3868 ActionDeleteRats (int argc
, char **argv
, Coord x
, Coord y
)
3870 char *function
= ARG (0);
3873 if (Settings
.RatWarn
)
3875 switch (GetFunctionID (function
))
3878 if (DeleteRats (false))
3879 SetChangedFlag (true);
3881 case F_SelectedRats
:
3883 if (DeleteRats (true))
3884 SetChangedFlag (true);
3891 /* --------------------------------------------------------------------------- */
3893 static const char autoplace_syntax
[] = "AutoPlaceSelected()";
3895 static const char autoplace_help
[] = "Auto-place selected components.";
3897 /* %start-doc actions AutoPlaceSelected
3899 Attempts to re-arrange the selected components such that the nets
3900 connecting them are minimized. Note that you cannot undo this.
3905 ActionAutoPlaceSelected (int argc
, char **argv
, Coord x
, Coord y
)
3908 if (gui
->confirm_dialog (_("Auto-placement can NOT be undone.\n"
3909 "Do you want to continue anyway?\n"), 0))
3911 if (AutoPlaceSelected ())
3912 SetChangedFlag (true);
3917 /* --------------------------------------------------------------------------- */
3919 static const char autoroute_syntax
[] = "AutoRoute(AllRats|SelectedRats)";
3921 static const char autoroute_help
[] = "Auto-route some or all rat lines.";
3923 /* %start-doc actions AutoRoute
3928 Attempt to autoroute all rats.
3931 Attempt to autoroute the selected rats.
3935 Before autorouting, it's important to set up a few things. First,
3936 make sure any layers you aren't using are disabled, else the
3937 autorouter may use them. Next, make sure the current line and via
3938 styles are set accordingly. Last, make sure "new lines clear
3939 polygons" is set, in case you eventually want to add a copper pour.
3941 Autorouting takes a while. During this time, the program may not be
3947 ActionAutoRoute (int argc
, char **argv
, Coord x
, Coord y
)
3949 char *function
= ARG (0);
3951 if (function
) /* one parameter */
3953 switch (GetFunctionID (function
))
3956 if (AutoRoute (false))
3957 SetChangedFlag (true);
3959 case F_SelectedRats
:
3961 if (AutoRoute (true))
3962 SetChangedFlag (true);
3969 /* --------------------------------------------------------------------------- */
3971 static const char markcrosshair_syntax
[] =
3973 "MarkCrosshair(Center)";
3975 static const char markcrosshair_help
[] = "Set/Reset the Crosshair mark.";
3977 /* %start-doc actions MarkCrosshair
3979 The ``mark'' is a small X-shaped target on the display which is
3980 treated like a second origin (the normal origin is the upper let
3981 corner of the board). The GUI will display a second set of
3982 coordinates for this mark, which tells you how far you are from it.
3984 If no argument is given, the mark is toggled - disabled if it was
3985 enabled, or enabled at the current cursor position of disabled. If
3986 the @code{Center} argument is given, the mark is moved to the current
3992 ActionMarkCrosshair (int argc
, char **argv
, Coord x
, Coord y
)
3994 char *function
= ARG (0);
3995 if (!function
|| !*function
)
3999 notify_mark_change (false);
4000 Marked
.status
= false;
4001 notify_mark_change (true);
4005 notify_mark_change (false);
4006 Marked
.status
= false;
4007 Marked
.status
= true;
4008 Marked
.X
= Crosshair
.X
;
4009 Marked
.Y
= Crosshair
.Y
;
4010 notify_mark_change (true);
4013 else if (GetFunctionID (function
) == F_Center
)
4015 notify_mark_change (false);
4016 Marked
.status
= true;
4017 Marked
.X
= Crosshair
.X
;
4018 Marked
.Y
= Crosshair
.Y
;
4019 notify_mark_change (true);
4024 /* --------------------------------------------------------------------------- */
4026 static const char changesize_syntax
[] =
4027 "ChangeSize(Object, delta)\n"
4028 "ChangeSize(SelectedObjects|Selected, delta)\n"
4029 "ChangeSize(SelectedLines|SelectedPins|SelectedVias, delta)\n"
4030 "ChangeSize(SelectedPads|SelectedTexts|SelectedNames, delta)\n"
4031 "ChangeSize(SelectedElements, delta)";
4033 static const char changesize_help
[] = "Changes the size of objects.";
4035 /* %start-doc actions ChangeSize
4037 For lines and arcs, this changes the width. For pins and vias, this
4038 changes the overall diameter of the copper annulus. For pads, this
4039 changes the width and, indirectly, the length. For texts and names,
4040 this changes the scaling factor. For elements, this changes the width
4041 of the silk layer lines and arcs for this element.
4046 ActionChangeSize (int argc
, char **argv
, Coord x
, Coord y
)
4048 char *function
= ARG (0);
4049 char *delta
= ARG (1);
4050 char *units
= ARG (2);
4051 bool absolute
; /* indicates if absolute size is given */
4054 if (function
&& delta
)
4056 value
= GetValue (delta
, units
, &absolute
);
4058 value
= delta
[0] == '-' ? -Settings
.increments
->size
4059 : Settings
.increments
->size
;
4060 switch (GetFunctionID (function
))
4065 void *ptr1
, *ptr2
, *ptr3
;
4068 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
4069 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4070 if (TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
4071 Message (_("Sorry, the object is locked\n"));
4072 if (ChangeObjectSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4073 SetChangedFlag (true);
4077 case F_SelectedVias
:
4078 if (ChangeSelectedSize (VIA_TYPE
, value
, absolute
))
4079 SetChangedFlag (true);
4082 case F_SelectedPins
:
4083 if (ChangeSelectedSize (PIN_TYPE
, value
, absolute
))
4084 SetChangedFlag (true);
4087 case F_SelectedPads
:
4088 if (ChangeSelectedSize (PAD_TYPE
, value
, absolute
))
4089 SetChangedFlag (true);
4092 case F_SelectedArcs
:
4093 if (ChangeSelectedSize (ARC_TYPE
, value
, absolute
))
4094 SetChangedFlag (true);
4097 case F_SelectedLines
:
4098 if (ChangeSelectedSize (LINE_TYPE
, value
, absolute
))
4099 SetChangedFlag (true);
4102 case F_SelectedTexts
:
4103 if (ChangeSelectedSize (TEXT_TYPE
, value
, absolute
))
4104 SetChangedFlag (true);
4107 case F_SelectedNames
:
4108 if (ChangeSelectedSize (ELEMENTNAME_TYPE
, value
, absolute
))
4109 SetChangedFlag (true);
4112 case F_SelectedElements
:
4113 if (ChangeSelectedSize (ELEMENT_TYPE
, value
, absolute
))
4114 SetChangedFlag (true);
4118 case F_SelectedObjects
:
4119 if (ChangeSelectedSize (CHANGESIZE_TYPES
, value
, absolute
))
4120 SetChangedFlag (true);
4127 /* --------------------------------------------------------------------------- */
4129 static const char changedrillsize_syntax
[] =
4130 "ChangeDrillSize(Object, delta)\n"
4131 "ChangeDrillSize(SelectedPins|SelectedVias|Selected|SelectedObjects, delta)";
4133 static const char changedrillsize_help
[] =
4134 "Changes the drilling hole size of objects.";
4136 /* %start-doc actions ChangeDrillSize
4141 ActionChange2ndSize (int argc
, char **argv
, Coord x
, Coord y
)
4143 char *function
= ARG (0);
4144 char *delta
= ARG (1);
4145 char *units
= ARG (2);
4149 if (function
&& delta
)
4151 value
= GetValue (delta
, units
, &absolute
);
4152 switch (GetFunctionID (function
))
4157 void *ptr1
, *ptr2
, *ptr3
;
4159 gui
->get_coords (_("Select an Object"), &x
, &y
);
4161 SearchScreen (x
, y
, CHANGE2NDSIZE_TYPES
,
4162 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4163 if (ChangeObject2ndSize
4164 (type
, ptr1
, ptr2
, ptr3
, value
, absolute
, true))
4165 SetChangedFlag (true);
4169 case F_SelectedVias
:
4170 if (ChangeSelected2ndSize (VIA_TYPE
, value
, absolute
))
4171 SetChangedFlag (true);
4174 case F_SelectedPins
:
4175 if (ChangeSelected2ndSize (PIN_TYPE
, value
, absolute
))
4176 SetChangedFlag (true);
4179 case F_SelectedObjects
:
4180 if (ChangeSelected2ndSize (PIN_TYPES
, value
, absolute
))
4181 SetChangedFlag (true);
4188 /* --------------------------------------------------------------------------- */
4190 static const char changeclearsize_syntax
[] =
4191 "ChangeClearSize(Object, delta)\n"
4192 "ChangeClearSize(SelectedPins|SelectedPads|SelectedVias, delta)\n"
4193 "ChangeClearSize(SelectedLines|SelectedArcs, delta\n"
4194 "ChangeClearSize(Selected|SelectedObjects, delta)";
4196 static const char changeclearsize_help
[] =
4197 "Changes the clearance size of objects.";
4199 /* %start-doc actions ChangeClearSize
4201 If the solder mask is currently showing, this action changes the
4202 solder mask clearance. If the mask is not showing, this action
4203 changes the polygon clearance.
4208 ActionChangeClearSize (int argc
, char **argv
, Coord x
, Coord y
)
4210 char *function
= ARG (0);
4211 char *delta
= ARG (1);
4212 char *units
= ARG (2);
4216 if (function
&& delta
)
4218 value
= 2 * GetValue (delta
, units
, &absolute
);
4220 value
= delta
[0] == '-' ? -Settings
.increments
->clear
4221 : Settings
.increments
->clear
;
4222 switch (GetFunctionID (function
))
4227 void *ptr1
, *ptr2
, *ptr3
;
4229 gui
->get_coords (_("Select an Object"), &x
, &y
);
4232 CHANGECLEARSIZE_TYPES
, &ptr1
, &ptr2
,
4234 if (ChangeObjectClearSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4235 SetChangedFlag (true);
4238 case F_SelectedVias
:
4239 if (ChangeSelectedClearSize (VIA_TYPE
, value
, absolute
))
4240 SetChangedFlag (true);
4242 case F_SelectedPads
:
4243 if (ChangeSelectedClearSize (PAD_TYPE
, value
, absolute
))
4244 SetChangedFlag (true);
4246 case F_SelectedPins
:
4247 if (ChangeSelectedClearSize (PIN_TYPE
, value
, absolute
))
4248 SetChangedFlag (true);
4250 case F_SelectedLines
:
4251 if (ChangeSelectedClearSize (LINE_TYPE
, value
, absolute
))
4252 SetChangedFlag (true);
4254 case F_SelectedArcs
:
4255 if (ChangeSelectedClearSize (ARC_TYPE
, value
, absolute
))
4256 SetChangedFlag (true);
4259 case F_SelectedObjects
:
4260 if (ChangeSelectedClearSize (CHANGECLEARSIZE_TYPES
, value
, absolute
))
4261 SetChangedFlag (true);
4268 /* --------------------------------------------------------------------------- */
4270 static const char minmaskgap_syntax
[] =
4271 "MinMaskGap(delta)\n"
4272 "MinMaskGap(Selected, delta)";
4274 static const char minmaskgap_help
[] =
4275 "Ensures the mask is a minimum distance from pins and pads.";
4277 /* %start-doc actions MinMaskGap
4279 Checks all specified pins and/or pads, and increases the mask if
4280 needed to ensure a minimum distance between the pin or pad edge and
4286 ActionMinMaskGap (int argc
, char **argv
, Coord x
, Coord y
)
4288 char *function
= ARG (0);
4289 char *delta
= ARG (1);
4290 char *units
= ARG (2);
4297 if (strcasecmp (function
, "Selected") == 0)
4298 flags
= SELECTEDFLAG
;
4305 value
= 2 * GetValue (delta
, units
, &absolute
);
4307 SaveUndoSerialNumber ();
4308 ELEMENT_LOOP (PCB
->Data
);
4312 if (!TEST_FLAGS (flags
, pin
))
4314 if (pin
->Mask
< pin
->Thickness
+ value
)
4316 ChangeObjectMaskSize (PIN_TYPE
, element
, pin
, 0,
4317 pin
->Thickness
+ value
, 1);
4318 RestoreUndoSerialNumber ();
4324 if (!TEST_FLAGS (flags
, pad
))
4326 if (pad
->Mask
< pad
->Thickness
+ value
)
4328 ChangeObjectMaskSize (PAD_TYPE
, element
, pad
, 0,
4329 pad
->Thickness
+ value
, 1);
4330 RestoreUndoSerialNumber ();
4336 VIA_LOOP (PCB
->Data
);
4338 if (!TEST_FLAGS (flags
, via
))
4340 if (via
->Mask
&& via
->Mask
< via
->Thickness
+ value
)
4342 ChangeObjectMaskSize (VIA_TYPE
, via
, 0, 0, via
->Thickness
+ value
, 1);
4343 RestoreUndoSerialNumber ();
4347 RestoreUndoSerialNumber ();
4348 IncrementUndoSerialNumber ();
4352 /* --------------------------------------------------------------------------- */
4354 static const char mincleargap_syntax
[] =
4355 "MinClearGap(delta)\n"
4356 "MinClearGap(Selected, delta)";
4358 static const char mincleargap_help
[] =
4359 "Ensures that polygons are a minimum distance from objects.";
4361 /* %start-doc actions MinClearGap
4363 Checks all specified objects, and increases the polygon clearance if
4364 needed to ensure a minimum distance between their edges and the
4370 ActionMinClearGap (int argc
, char **argv
, Coord x
, Coord y
)
4372 char *function
= ARG (0);
4373 char *delta
= ARG (1);
4374 char *units
= ARG (2);
4381 if (strcasecmp (function
, "Selected") == 0)
4382 flags
= SELECTEDFLAG
;
4389 value
= 2 * GetValue (delta
, units
, &absolute
);
4391 SaveUndoSerialNumber ();
4392 ELEMENT_LOOP (PCB
->Data
);
4396 if (!TEST_FLAGS (flags
, pin
))
4398 if (pin
->Clearance
< value
)
4400 ChangeObjectClearSize (PIN_TYPE
, element
, pin
, 0,
4402 RestoreUndoSerialNumber ();
4408 if (!TEST_FLAGS (flags
, pad
))
4410 if (pad
->Clearance
< value
)
4412 ChangeObjectClearSize (PAD_TYPE
, element
, pad
, 0,
4414 RestoreUndoSerialNumber ();
4420 VIA_LOOP (PCB
->Data
);
4422 if (!TEST_FLAGS (flags
, via
))
4424 if (via
->Clearance
< value
)
4426 ChangeObjectClearSize (VIA_TYPE
, via
, 0, 0, value
, 1);
4427 RestoreUndoSerialNumber ();
4431 ALLLINE_LOOP (PCB
->Data
);
4433 if (!TEST_FLAGS (flags
, line
))
4435 if (line
->Clearance
< value
)
4437 ChangeObjectClearSize (LINE_TYPE
, layer
, line
, 0, value
, 1);
4438 RestoreUndoSerialNumber ();
4442 ALLARC_LOOP (PCB
->Data
);
4444 if (!TEST_FLAGS (flags
, arc
))
4446 if (arc
->Clearance
< value
)
4448 ChangeObjectClearSize (ARC_TYPE
, layer
, arc
, 0, value
, 1);
4449 RestoreUndoSerialNumber ();
4453 RestoreUndoSerialNumber ();
4454 IncrementUndoSerialNumber ();
4458 /* --------------------------------------------------------------------------- */
4460 static const char changepinname_syntax
[] =
4461 "ChangePinName(ElementName,PinNumber,PinName)";
4463 static const char changepinname_help
[] =
4464 "Sets the name of a specific pin on a specific element.";
4466 /* %start-doc actions ChangePinName
4468 This can be especially useful for annotating pin names from a
4469 schematic to the layout without requiring knowledge of the pcb file
4473 ChangePinName(U3, 7, VCC)
4479 ActionChangePinName (int argc
, char **argv
, Coord x
, Coord y
)
4482 char *refdes
, *pinnum
, *pinname
;
4486 AFAIL (changepinname
);
4493 ELEMENT_LOOP (PCB
->Data
);
4495 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
4499 if (NSTRCMP (pinnum
, pin
->Number
) == 0)
4501 AddObjectToChangeNameUndoList (PIN_TYPE
, NULL
, NULL
,
4504 * Note: we can't free() pin->Name first because
4505 * it is used in the undo list
4507 pin
->Name
= strdup (pinname
);
4508 SetChangedFlag (true);
4516 if (NSTRCMP (pinnum
, pad
->Number
) == 0)
4518 AddObjectToChangeNameUndoList (PAD_TYPE
, NULL
, NULL
,
4521 * Note: we can't free() pad->Name first because
4522 * it is used in the undo list
4524 pad
->Name
= strdup (pinname
);
4525 SetChangedFlag (true);
4534 * done with our action so increment the undo # if we actually
4540 defer_needs_update
= 1;
4543 IncrementUndoSerialNumber ();
4544 gui
->invalidate_all ();
4551 /* --------------------------------------------------------------------------- */
4553 static const char changename_syntax
[] =
4554 "ChangeName(Object)\n"
4555 "ChangeName(Layout|Layer)";
4557 static const char changename_help
[] = "Sets the name of objects.";
4559 /* %start-doc actions ChangeName
4564 Changes the name of the element under the cursor.
4567 Changes the name of the layout. This is printed on the fab drawings.
4570 Changes the name of the currently active layer.
4577 ActionChangeName (int argc
, char **argv
, Coord x
, Coord y
)
4579 char *function
= ARG (0);
4584 switch (GetFunctionID (function
))
4586 /* change the name of an object */
4590 void *ptr1
, *ptr2
, *ptr3
;
4592 gui
->get_coords (_("Select an Object"), &x
, &y
);
4594 SearchScreen (x
, y
, CHANGENAME_TYPES
,
4595 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4597 SaveUndoSerialNumber ();
4598 if (QueryInputAndChangeObjectName (type
, ptr1
, ptr2
, ptr3
))
4600 SetChangedFlag (true);
4601 if (type
== ELEMENT_TYPE
)
4603 RubberbandType
*ptr
;
4606 RestoreUndoSerialNumber ();
4607 Crosshair
.AttachedObject
.RubberbandN
= 0;
4608 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
4609 ptr
= Crosshair
.AttachedObject
.Rubberband
;
4610 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
;
4614 EraseRat ((RatType
*) ptr
->Line
);
4615 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
4616 ptr
->Line
, ptr
->Line
,
4619 IncrementUndoSerialNumber ();
4627 /* change the layout's name */
4630 gui
->prompt_for (_("Enter the layout name:"), EMPTY (PCB
->Name
));
4631 /* NB: ChangeLayoutName takes ownership of the passed memory */
4632 if (name
&& ChangeLayoutName (name
))
4633 SetChangedFlag (true);
4636 /* change the name of the active layer */
4638 name
= gui
->prompt_for (_("Enter the layer name:"),
4639 EMPTY (CURRENT
->Name
));
4640 /* NB: ChangeLayerName takes ownership of the passed memory */
4641 if (name
&& ChangeLayerName (CURRENT
, name
))
4642 SetChangedFlag (true);
4650 /* --------------------------------------------------------------------------- */
4652 static const char morphpolygon_syntax
[] = "MorphPolygon(Object|Selected)";
4654 static const char morphpolygon_help
[] =
4655 "Converts dead polygon islands into separate polygons.";
4657 /* %start-doc actions MorphPolygon
4659 If a polygon is divided into unconnected "islands", you can use
4660 this command to convert the otherwise disappeared islands into
4661 separate polygons. Be sure the cursor is over a portion of the
4662 polygon that remains visible. Very small islands that may flake
4663 off are automatically deleted.
4668 ActionMorphPolygon (int argc
, char **argv
, Coord x
, Coord y
)
4670 char *function
= ARG (0);
4673 switch (GetFunctionID (function
))
4678 void *ptr1
, *ptr2
, *ptr3
;
4680 gui
->get_coords (_("Select an Object"), &x
, &y
);
4681 if ((type
= SearchScreen (x
, y
, POLYGON_TYPE
,
4682 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4684 MorphPolygon ((LayerType
*) ptr1
, (PolygonType
*) ptr3
);
4686 IncrementUndoSerialNumber ();
4691 case F_SelectedObjects
:
4692 ALLPOLYGON_LOOP (PCB
->Data
);
4694 if (TEST_FLAG (SELECTEDFLAG
, polygon
))
4695 MorphPolygon (layer
, polygon
);
4699 IncrementUndoSerialNumber ();
4706 /* --------------------------------------------------------------------------- */
4708 static const char togglehidename_syntax
[] =
4709 "ToggleHideName(Object|SelectedElements)";
4711 static const char togglehidename_help
[] =
4712 "Toggles the visibility of element names.";
4714 /* %start-doc actions ToggleHideName
4716 If names are hidden you won't see them on the screen and they will not
4717 appear on the silk layer when you print the layout.
4722 ActionToggleHideName (int argc
, char **argv
, Coord x
, Coord y
)
4724 char *function
= ARG (0);
4725 if (function
&& PCB
->ElementOn
)
4727 switch (GetFunctionID (function
))
4732 void *ptr1
, *ptr2
, *ptr3
;
4734 gui
->get_coords (_("Select an Object"), &x
, &y
);
4735 if ((type
= SearchScreen (x
, y
, ELEMENT_TYPE
,
4736 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4738 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr3
);
4739 EraseElementName ((ElementType
*) ptr2
);
4740 TOGGLE_FLAG (HIDENAMEFLAG
, (ElementType
*) ptr2
);
4741 DrawElementName ((ElementType
*) ptr2
);
4743 IncrementUndoSerialNumber ();
4747 case F_SelectedElements
:
4750 bool changed
= false;
4751 ELEMENT_LOOP (PCB
->Data
);
4753 if ((TEST_FLAG (SELECTEDFLAG
, element
) ||
4754 TEST_FLAG (SELECTEDFLAG
,
4755 &NAMEONPCB_TEXT (element
)))
4756 && (FRONT (element
) || PCB
->InvisibleObjectsOn
))
4758 AddObjectToFlagUndoList (ELEMENT_TYPE
, element
,
4760 EraseElementName (element
);
4761 TOGGLE_FLAG (HIDENAMEFLAG
, element
);
4762 DrawElementName (element
);
4770 IncrementUndoSerialNumber ();
4778 /* --------------------------------------------------------------------------- */
4780 static const char changejoin_syntax
[] =
4781 "ChangeJoin(ToggleObject|SelectedLines|SelectedArcs|Selected)";
4783 static const char changejoin_help
[] =
4784 "Changes the join (clearance through polygons) of objects.";
4786 /* %start-doc actions ChangeJoin
4788 The join flag determines whether a line or arc, drawn to intersect a
4789 polygon, electrically connects to the polygon or not. When joined,
4790 the line/arc is simply drawn over the polygon, making an electrical
4791 connection. When not joined, a gap is drawn between the line and the
4792 polygon, insulating them from each other.
4797 ActionChangeJoin (int argc
, char **argv
, Coord x
, Coord y
)
4799 char *function
= ARG (0);
4802 switch (GetFunctionID (function
))
4804 case F_ToggleObject
:
4808 void *ptr1
, *ptr2
, *ptr3
;
4810 gui
->get_coords (_("Select an Object"), &x
, &y
);
4812 SearchScreen (x
, y
, CHANGEJOIN_TYPES
,
4813 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4814 if (ChangeObjectJoin (type
, ptr1
, ptr2
, ptr3
))
4815 SetChangedFlag (true);
4819 case F_SelectedLines
:
4820 if (ChangeSelectedJoin (LINE_TYPE
))
4821 SetChangedFlag (true);
4824 case F_SelectedArcs
:
4825 if (ChangeSelectedJoin (ARC_TYPE
))
4826 SetChangedFlag (true);
4830 case F_SelectedObjects
:
4831 if (ChangeSelectedJoin (CHANGEJOIN_TYPES
))
4832 SetChangedFlag (true);
4839 /* --------------------------------------------------------------------------- */
4841 static const char changesquare_syntax
[] =
4842 "ChangeSquare(ToggleObject)\n"
4843 "ChangeSquare(SelectedElements|SelectedPins)\n"
4844 "ChangeSquare(Selected|SelectedObjects)";
4846 static const char changesquare_help
[] =
4847 "Changes the square flag of pins and pads.";
4849 /* %start-doc actions ChangeSquare
4851 Note that @code{Pins} means both pins and pads.
4858 ActionChangeSquare (int argc
, char **argv
, Coord x
, Coord y
)
4860 char *function
= ARG (0);
4863 switch (GetFunctionID (function
))
4865 case F_ToggleObject
:
4869 void *ptr1
, *ptr2
, *ptr3
;
4871 gui
->get_coords (_("Select an Object"), &x
, &y
);
4873 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4874 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4875 if (ChangeObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4876 SetChangedFlag (true);
4880 case F_SelectedElements
:
4881 if (ChangeSelectedSquare (ELEMENT_TYPE
))
4882 SetChangedFlag (true);
4885 case F_SelectedPins
:
4886 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4887 SetChangedFlag (true);
4891 case F_SelectedObjects
:
4892 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4893 SetChangedFlag (true);
4900 /* --------------------------------------------------------------------------- */
4902 static const char setsquare_syntax
[] =
4903 "SetSquare(ToggleObject|SelectedElements|SelectedPins)";
4905 static const char setsquare_help
[] = "sets the square-flag of objects.";
4907 /* %start-doc actions SetSquare
4909 Note that @code{Pins} means pins and pads.
4916 ActionSetSquare (int argc
, char **argv
, Coord x
, Coord y
)
4918 char *function
= ARG (0);
4919 if (function
&& *function
)
4921 switch (GetFunctionID (function
))
4923 case F_ToggleObject
:
4927 void *ptr1
, *ptr2
, *ptr3
;
4929 gui
->get_coords (_("Select an Object"), &x
, &y
);
4931 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4932 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4933 if (SetObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4934 SetChangedFlag (true);
4938 case F_SelectedElements
:
4939 if (SetSelectedSquare (ELEMENT_TYPE
))
4940 SetChangedFlag (true);
4943 case F_SelectedPins
:
4944 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4945 SetChangedFlag (true);
4949 case F_SelectedObjects
:
4950 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4951 SetChangedFlag (true);
4958 /* --------------------------------------------------------------------------- */
4960 static const char clearsquare_syntax
[] =
4961 "ClearSquare(ToggleObject|SelectedElements|SelectedPins)";
4963 static const char clearsquare_help
[] =
4964 "Clears the square-flag of pins and pads.";
4966 /* %start-doc actions ClearSquare
4968 Note that @code{Pins} means pins and pads.
4975 ActionClearSquare (int argc
, char **argv
, Coord x
, Coord y
)
4977 char *function
= ARG (0);
4978 if (function
&& *function
)
4980 switch (GetFunctionID (function
))
4982 case F_ToggleObject
:
4986 void *ptr1
, *ptr2
, *ptr3
;
4988 gui
->get_coords (_("Select an Object"), &x
, &y
);
4990 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4991 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4992 if (ClrObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4993 SetChangedFlag (true);
4997 case F_SelectedElements
:
4998 if (ClrSelectedSquare (ELEMENT_TYPE
))
4999 SetChangedFlag (true);
5002 case F_SelectedPins
:
5003 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
5004 SetChangedFlag (true);
5008 case F_SelectedObjects
:
5009 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
5010 SetChangedFlag (true);
5017 /* --------------------------------------------------------------------------- */
5019 static const char changeoctagon_syntax
[] =
5020 "ChangeOctagon(Object|ToggleObject|SelectedObjects|Selected)\n"
5021 "ChangeOctagon(SelectedElements|SelectedPins|SelectedVias)";
5023 static const char changeoctagon_help
[] =
5024 "Changes the octagon-flag of pins and vias.";
5026 /* %start-doc actions ChangeOctagon
5033 ActionChangeOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5035 char *function
= ARG (0);
5038 switch (GetFunctionID (function
))
5040 case F_ToggleObject
:
5044 void *ptr1
, *ptr2
, *ptr3
;
5046 gui
->get_coords (_("Select an Object"), &x
, &y
);
5048 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5049 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5050 if (ChangeObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5051 SetChangedFlag (true);
5055 case F_SelectedElements
:
5056 if (ChangeSelectedOctagon (ELEMENT_TYPE
))
5057 SetChangedFlag (true);
5060 case F_SelectedPins
:
5061 if (ChangeSelectedOctagon (PIN_TYPE
))
5062 SetChangedFlag (true);
5065 case F_SelectedVias
:
5066 if (ChangeSelectedOctagon (VIA_TYPE
))
5067 SetChangedFlag (true);
5071 case F_SelectedObjects
:
5072 if (ChangeSelectedOctagon (PIN_TYPES
))
5073 SetChangedFlag (true);
5080 /* --------------------------------------------------------------------------- */
5082 static const char setoctagon_syntax
[] =
5083 "SetOctagon(Object|ToggleObject|SelectedElements|Selected)";
5085 static const char setoctagon_help
[] = "Sets the octagon-flag of objects.";
5087 /* %start-doc actions SetOctagon
5094 ActionSetOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5096 char *function
= ARG (0);
5099 switch (GetFunctionID (function
))
5101 case F_ToggleObject
:
5105 void *ptr1
, *ptr2
, *ptr3
;
5107 gui
->get_coords (_("Select an Object"), &x
, &y
);
5109 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5110 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5111 if (SetObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5112 SetChangedFlag (true);
5116 case F_SelectedElements
:
5117 if (SetSelectedOctagon (ELEMENT_TYPE
))
5118 SetChangedFlag (true);
5121 case F_SelectedPins
:
5122 if (SetSelectedOctagon (PIN_TYPE
))
5123 SetChangedFlag (true);
5126 case F_SelectedVias
:
5127 if (SetSelectedOctagon (VIA_TYPE
))
5128 SetChangedFlag (true);
5132 case F_SelectedObjects
:
5133 if (SetSelectedOctagon (PIN_TYPES
))
5134 SetChangedFlag (true);
5141 /* --------------------------------------------------------------------------- */
5143 static const char clearoctagon_syntax
[] =
5144 "ClearOctagon(ToggleObject|Object|SelectedObjects|Selected)\n"
5145 "ClearOctagon(SelectedElements|SelectedPins|SelectedVias)";
5147 static const char clearoctagon_help
[] =
5148 "Clears the octagon-flag of pins and vias.";
5150 /* %start-doc actions ClearOctagon
5157 ActionClearOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5159 char *function
= ARG (0);
5162 switch (GetFunctionID (function
))
5164 case F_ToggleObject
:
5168 void *ptr1
, *ptr2
, *ptr3
;
5170 gui
->get_coords (_("Select an Object"), &x
, &y
);
5172 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGEOCTAGON_TYPES
,
5173 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5174 if (ClrObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5175 SetChangedFlag (true);
5179 case F_SelectedElements
:
5180 if (ClrSelectedOctagon (ELEMENT_TYPE
))
5181 SetChangedFlag (true);
5184 case F_SelectedPins
:
5185 if (ClrSelectedOctagon (PIN_TYPE
))
5186 SetChangedFlag (true);
5189 case F_SelectedVias
:
5190 if (ClrSelectedOctagon (VIA_TYPE
))
5191 SetChangedFlag (true);
5195 case F_SelectedObjects
:
5196 if (ClrSelectedOctagon (PIN_TYPES
))
5197 SetChangedFlag (true);
5204 /* --------------------------------------------------------------------------- */
5206 static const char changehold_syntax
[] =
5207 "ChangeHole(ToggleObject|Object|SelectedVias|Selected)";
5209 static const char changehold_help
[] = "Changes the hole flag of objects.";
5211 /* %start-doc actions ChangeHole
5213 The "hole flag" of a via determines whether the via is a
5214 plated-through hole (not set), or an unplated hole (set).
5219 ActionChangeHole (int argc
, char **argv
, Coord x
, Coord y
)
5221 char *function
= ARG (0);
5224 switch (GetFunctionID (function
))
5226 case F_ToggleObject
:
5230 void *ptr1
, *ptr2
, *ptr3
;
5232 gui
->get_coords (_("Select an Object"), &x
, &y
);
5233 if ((type
= SearchScreen (x
, y
, VIA_TYPE
,
5234 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5235 && ChangeHole ((PinType
*) ptr3
))
5236 IncrementUndoSerialNumber ();
5240 case F_SelectedVias
:
5242 if (ChangeSelectedHole ())
5243 SetChangedFlag (true);
5250 /* --------------------------------------------------------------------------- */
5252 static const char changepaste_syntax
[] =
5253 "ChangePaste(ToggleObject|Object|SelectedPads|Selected)";
5255 static const char changepaste_help
[] = "Changes the no paste flag of objects.";
5257 /* %start-doc actions ChangePaste
5259 The "no paste flag" of a pad determines whether the solderpaste
5260 stencil will have an opening for the pad (no set) or if there wil be
5261 no solderpaste on the pad (set). This is used for things such as
5267 ActionChangePaste (int argc
, char **argv
, Coord x
, Coord y
)
5269 char *function
= ARG (0);
5272 switch (GetFunctionID (function
))
5274 case F_ToggleObject
:
5278 void *ptr1
, *ptr2
, *ptr3
;
5280 gui
->get_coords (_("Select an Object"), &x
, &y
);
5281 if ((type
= SearchScreen (x
, y
, PAD_TYPE
,
5282 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5283 && ChangePaste ((PadType
*) ptr3
))
5284 IncrementUndoSerialNumber ();
5288 case F_SelectedPads
:
5290 if (ChangeSelectedPaste ())
5291 SetChangedFlag (true);
5298 /* --------------------------------------------------------------------------- */
5300 static const char select_syntax
[] =
5301 "Select(Object|ToggleObject)\n"
5302 "Select(All|Block|Connection)\n"
5303 "Select(ElementByName|ObjectByName|PadByName|PinByName)\n"
5304 "Select(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5305 "Select(TextByName|ViaByName|NetByName)\n"
5306 "Select(TextByName|ViaByName|NetByName, Name)\n"
5309 static const char select_help
[] = "Toggles or sets the selection.";
5311 /* %start-doc actions Select
5323 These all rely on having a regular expression parser built into
5324 @code{pcb}. If the name is not specified then the user is prompted
5325 for a pattern, and all objects that match the pattern and are of the
5326 type specified are selected.
5330 Selects the object under the cursor.
5333 Selects all objects in a rectangle indicated by the cursor.
5336 Selects all objects on the board.
5339 Selects all connections with the ``found'' flag set.
5342 Converts the selected objects to an element. This uses the highest
5343 numbered paste buffer.
5350 ActionSelect (int argc
, char **argv
, Coord x
, Coord y
)
5352 char *function
= ARG (0);
5355 switch (GetFunctionID (function
))
5357 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5359 /* select objects by their names */
5360 case F_ElementByName
:
5361 type
= ELEMENT_TYPE
;
5363 case F_ObjectByName
:
5384 char *pattern
= ARG (1);
5388 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5390 if (SelectObjectByName (type
, pattern
, true))
5391 SetChangedFlag (true);
5392 if (ARG (1) == NULL
)
5397 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5399 /* select a single object */
5400 case F_ToggleObject
:
5402 if (SelectObject ())
5403 SetChangedFlag (true);
5406 /* all objects in block */
5411 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5412 Crosshair
.AttachedBox
.Point2
.X
);
5413 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5414 Crosshair
.AttachedBox
.Point2
.Y
);
5415 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5416 Crosshair
.AttachedBox
.Point2
.X
);
5417 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5418 Crosshair
.AttachedBox
.Point2
.Y
);
5419 notify_crosshair_change (false);
5421 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5422 SelectBlock (&box
, true))
5424 SetChangedFlag (true);
5425 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5427 notify_crosshair_change (true);
5431 /* select all visible objects */
5436 box
.X1
= -MAX_COORD
;
5437 box
.Y1
= -MAX_COORD
;
5440 if (SelectBlock (&box
, true))
5441 SetChangedFlag (true);
5445 /* all found connections */
5447 if (SelectConnection (true))
5450 IncrementUndoSerialNumber ();
5451 SetChangedFlag (true);
5458 Note
.Buffer
= Settings
.BufferNumber
;
5459 SetBufferNumber (MAX_BUFFER
- 1);
5460 ClearBuffer (PASTEBUFFER
);
5461 gui
->get_coords (_("Select the Element's Mark Location"), &x
, &y
);
5462 x
= GridFit (x
, PCB
->Grid
, PCB
->GridOffsetX
);
5463 y
= GridFit (y
, PCB
->Grid
, PCB
->GridOffsetY
);
5464 AddSelectedToBuffer (PASTEBUFFER
, x
, y
, true);
5465 SaveUndoSerialNumber ();
5467 ConvertBufferToElement (PASTEBUFFER
);
5468 RestoreUndoSerialNumber ();
5469 CopyPastebufferToLayout (x
, y
);
5470 SetBufferNumber (Note
.Buffer
);
5482 /* FLAG(have_regex,FlagHaveRegex,0) */
5484 FlagHaveRegex (int parm
)
5486 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5493 /* --------------------------------------------------------------------------- */
5495 static const char unselect_syntax
[] =
5496 "Unselect(All|Block|Connection)\n"
5497 "Unselect(ElementByName|ObjectByName|PadByName|PinByName)\n"
5498 "Unselect(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5499 "Unselect(TextByName|ViaByName)\n"
5500 "Unselect(TextByName|ViaByName, Name)\n";
5502 static const char unselect_help
[] =
5503 "Unselects the object at the pointer location or the specified objects.";
5505 /* %start-doc actions Unselect
5510 Unselect all objects.
5513 Unselect all objects in a rectangle given by the cursor.
5516 Unselect all connections with the ``found'' flag set.
5525 These all rely on having a regular expression parser built into
5526 @code{pcb}. If the name is not specified then the user is prompted
5527 for a pattern, and all objects that match the pattern and are of the
5528 type specified are unselected.
5536 ActionUnselect (int argc
, char **argv
, Coord x
, Coord y
)
5538 char *function
= ARG (0);
5541 switch (GetFunctionID (function
))
5543 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5545 /* select objects by their names */
5546 case F_ElementByName
:
5547 type
= ELEMENT_TYPE
;
5549 case F_ObjectByName
:
5570 char *pattern
= ARG (1);
5574 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5576 if (SelectObjectByName (type
, pattern
, false))
5577 SetChangedFlag (true);
5578 if (ARG (1) == NULL
)
5583 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5585 /* all objects in block */
5590 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5591 Crosshair
.AttachedBox
.Point2
.X
);
5592 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5593 Crosshair
.AttachedBox
.Point2
.Y
);
5594 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5595 Crosshair
.AttachedBox
.Point2
.X
);
5596 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5597 Crosshair
.AttachedBox
.Point2
.Y
);
5598 notify_crosshair_change (false);
5600 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5601 SelectBlock (&box
, false))
5603 SetChangedFlag (true);
5604 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5606 notify_crosshair_change (true);
5610 /* unselect all visible objects */
5615 box
.X1
= -MAX_COORD
;
5616 box
.Y1
= -MAX_COORD
;
5619 if (SelectBlock (&box
, false))
5620 SetChangedFlag (true);
5624 /* all found connections */
5626 if (SelectConnection (false))
5629 IncrementUndoSerialNumber ();
5630 SetChangedFlag (true);
5643 /* --------------------------------------------------------------------------- */
5645 static const char saveto_syntax
[] =
5646 "SaveTo(Layout|LayoutAs,filename)\n"
5647 "SaveTo(AllConnections|AllUnusedPins|ElementConnections,filename)\n"
5648 "SaveTo(PasteBuffer,filename)";
5650 static const char saveto_help
[] = "Saves data to a file.";
5652 /* %start-doc actions SaveTo
5657 Saves the current layout.
5660 Saves the current layout, and remembers the filename used.
5662 @item AllConnections
5663 Save all connections to a file.
5666 List all unused pins to a file.
5668 @item ElementConnections
5669 Save connections to the element at the cursor to a file.
5672 Save the content of the active Buffer to a file. This is the graphical way to create a footprint.
5679 ActionSaveTo (int argc
, char **argv
, Coord x
, Coord y
)
5687 if (strcasecmp (function
, "Layout") == 0)
5689 if (SavePCB (PCB
->Filename
) == 0)
5690 SetChangedFlag (false);
5697 if (strcasecmp (function
, "LayoutAs") == 0)
5699 if (SavePCB (name
) == 0)
5701 SetChangedFlag (false);
5702 free (PCB
->Filename
);
5703 PCB
->Filename
= strdup (name
);
5704 if (gui
->notify_filename_changed
!= NULL
)
5705 gui
->notify_filename_changed ();
5710 if (strcasecmp (function
, "AllConnections") == 0)
5714 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5716 LookupConnectionsToAllElements (fp
);
5718 SetChangedFlag (true);
5723 if (strcasecmp (function
, "AllUnusedPins") == 0)
5727 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5729 LookupUnusedPins (fp
);
5731 SetChangedFlag (true);
5736 if (strcasecmp (function
, "ElementConnections") == 0)
5738 ElementType
*element
;
5743 if ((SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
5744 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
5746 element
= (ElementType
*) ptrtmp
;
5748 CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5750 LookupElementConnections (element
, fp
);
5752 SetChangedFlag (true);
5758 if (strcasecmp (function
, "PasteBuffer") == 0)
5760 return SaveBufferElements (name
);
5766 /* --------------------------------------------------------------------------- */
5768 static const char savesettings_syntax
[] =
5770 "SaveSettings(local)";
5772 static const char savesettings_help
[] = "Saves settings.";
5774 /* %start-doc actions SaveSettings
5776 If you pass no arguments, the settings are stored in
5777 @code{$HOME/.pcb/settings}. If you pass the word @code{local} they're
5778 saved in @code{./pcb.settings}.
5783 ActionSaveSettings (int argc
, char **argv
, Coord x
, Coord y
)
5785 int locally
= argc
> 0 ? (strncasecmp (argv
[0], "local", 5) == 0) : 0;
5786 hid_save_settings (locally
);
5790 /* --------------------------------------------------------------------------- */
5792 static const char loadfrom_syntax
[] =
5793 "LoadFrom(Layout|LayoutToBuffer|ElementToBuffer|Netlist|Revert,filename)";
5795 static const char loadfrom_help
[] = "Load layout data from a file.";
5797 /* %start-doc actions LoadFrom
5799 This action assumes you know what the filename is. The various GUIs
5800 should have a similar @code{Load} action where the filename is
5801 optional, and will provide their own file selection mechanism to let
5802 you choose the file name.
5807 Loads an entire PCB layout, replacing the current one.
5809 @item LayoutToBuffer
5810 Loads an entire PCB layout to the paste buffer.
5812 @item ElementToBuffer
5813 Loads the given element file into the paste buffer. Element files
5814 contain only a single @code{Element} definition, such as the
5815 ``newlib'' library uses.
5818 Loads a new netlist, replacing any current netlist.
5821 Re-loads the current layout from its disk file, reverting any changes
5829 ActionLoadFrom (int argc
, char **argv
, Coord x
, Coord y
)
5840 if (strcasecmp (function
, "ElementToBuffer") == 0)
5842 notify_crosshair_change (false);
5843 if (LoadElementToBuffer (PASTEBUFFER
, name
, true))
5844 SetMode (PASTEBUFFER_MODE
);
5845 notify_crosshair_change (true);
5848 else if (strcasecmp (function
, "LayoutToBuffer") == 0)
5850 notify_crosshair_change (false);
5851 if (LoadLayoutToBuffer (PASTEBUFFER
, name
))
5852 SetMode (PASTEBUFFER_MODE
);
5853 notify_crosshair_change (true);
5856 else if (strcasecmp (function
, "Layout") == 0)
5858 if (!PCB
->Changed
||
5859 gui
->confirm_dialog (_("OK to override layout data?"), 0))
5863 else if (strcasecmp (function
, "Netlist") == 0)
5865 if (PCB
->Netlistname
)
5866 free (PCB
->Netlistname
);
5867 PCB
->Netlistname
= StripWhiteSpaceAndDup (name
);
5868 FreeLibraryMemory (&PCB
->NetlistLib
);
5869 ImportNetlist (PCB
->Netlistname
);
5872 else if (strcasecmp (function
, "Revert") == 0 && PCB
->Filename
5874 || gui
->confirm_dialog (_("OK to override changes?"), 0)))
5882 /* --------------------------------------------------------------------------- */
5884 static const char new_syntax
[] = "New([name])";
5886 static const char new_help
[] = "Starts a new layout.";
5888 /* %start-doc actions New
5890 If a name is not given, one is prompted for.
5895 ActionNew (int argc
, char **argv
, Coord x
, Coord y
)
5897 char *name
= ARG (0);
5899 if (!PCB
->Changed
|| gui
->confirm_dialog (_("OK to clear layout data?"), 0))
5902 name
= strdup (name
);
5904 name
= gui
->prompt_for (_("Enter the layout name:"), "");
5909 notify_crosshair_change (false);
5910 /* do emergency saving
5911 * clear the old struct and allocate memory for the new one
5913 if (PCB
->Changed
&& Settings
.SaveInTMP
)
5917 PCB
= CreateNewPCB (true);
5918 PCB
->Data
->LayerN
= DEF_LAYER
;
5919 CreateNewPCBPost (PCB
, 1);
5921 /* setup the new name and reset some values to default */
5925 ResetStackAndVisibility ();
5926 SetCrosshairRange (0, 0, PCB
->MaxWidth
, PCB
->MaxHeight
);
5927 CenterDisplay (PCB
->MaxWidth
/ 2, PCB
->MaxHeight
/ 2);
5930 hid_action ("PCBChanged");
5931 notify_crosshair_change (true);
5937 /* ---------------------------------------------------------------------------
5938 * no operation, just for testing purposes
5939 * syntax: Bell(volume)
5942 ActionBell (char *volume
)
5947 /* --------------------------------------------------------------------------- */
5949 static const char pastebuffer_syntax
[] =
5950 "PasteBuffer(AddSelected|Clear|1..MAX_BUFFER)\n"
5951 "PasteBuffer(Rotate, 1..3)\n"
5952 "PasteBuffer(Convert|Save|Restore|Mirror)\n"
5953 "PasteBuffer(ToLayout, X, Y, units)";
5955 static const char pastebuffer_help
[] =
5956 "Various operations on the paste buffer.";
5958 /* %start-doc actions PasteBuffer
5960 There are a number of paste buffers; the actual limit is a
5961 compile-time constant @code{MAX_BUFFER} in @file{globalconst.h}. It
5962 is currently @code{5}. One of these is the ``current'' paste buffer,
5963 often referred to as ``the'' paste buffer.
5968 Copies the selected objects to the current paste buffer.
5971 Remove all objects from the current paste buffer.
5974 Convert the current paste buffer to an element. Vias are converted to
5975 pins, lines are converted to pads.
5978 Convert any elements in the paste buffer back to vias and lines.
5981 Flip all objects in the paste buffer vertically (up/down flip). To mirror
5982 horizontally, combine this with rotations.
5985 Rotates the current buffer. The number to pass is 1..3, where 1 means
5986 90 degrees counter clockwise, 2 means 180 degrees, and 3 means 90
5987 degrees clockwise (270 CCW).
5990 Saves any elements in the current buffer to the indicated file.
5993 Pastes any elements in the current buffer to the indicated X, Y
5994 coordinates in the layout. The @code{X} and @code{Y} are treated like
5995 @code{delta} is for many other objects. For each, if it's prefixed by
5996 @code{+} or @code{-}, then that amount is relative to the last
5997 location. Otherwise, it's absolute. Units can be
5998 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
5999 units, currently 1/100 mil.
6003 Selects the given buffer to be the current paste buffer.
6010 ActionPasteBuffer (int argc
, char **argv
, Coord x
, Coord y
)
6012 char *function
= argc
? argv
[0] : (char *)"";
6013 char *sbufnum
= argc
> 1 ? argv
[1] : (char *)"";
6015 static char *default_file
= NULL
;
6018 notify_crosshair_change (false);
6021 switch (GetFunctionID (function
))
6023 /* clear contents of paste buffer */
6025 ClearBuffer (PASTEBUFFER
);
6028 /* copies objects to paste buffer */
6030 AddSelectedToBuffer (PASTEBUFFER
, 0, 0, false);
6033 /* converts buffer contents into an element */
6035 ConvertBufferToElement (PASTEBUFFER
);
6038 /* break up element for editing */
6040 SmashBufferElement (PASTEBUFFER
);
6045 MirrorBuffer (PASTEBUFFER
);
6051 RotateBuffer (PASTEBUFFER
, (BYTE
) atoi (sbufnum
));
6052 SetCrosshairRangeToBuffer ();
6057 if (PASTEBUFFER
->Data
->ElementN
== 0)
6059 Message (_("Buffer has no elements!\n"));
6065 name
= gui
->fileselect (_("Save Paste Buffer As ..."),
6066 _("Choose a file to save the contents of the\n"
6067 "paste buffer to.\n"),
6068 default_file
, ".fp", "footprint",
6073 free (default_file
);
6074 default_file
= NULL
;
6078 default_file
= strdup (name
);
6089 if ((exist
= fopen (name
, "r")))
6093 confirm_dialog (_("File exists! Ok to overwrite?"), 0))
6094 SaveBufferElements (name
);
6097 SaveBufferElements (name
);
6099 if (free_name
&& name
)
6106 static Coord oldx
= 0, oldy
= 0;
6114 else if (argc
== 3 || argc
== 4)
6116 x
= GetValue (ARG (1), ARG (3), &absolute
);
6119 y
= GetValue (ARG (2), ARG (3), &absolute
);
6125 notify_crosshair_change (true);
6126 AFAIL (pastebuffer
);
6131 if (CopyPastebufferToLayout (x
, y
))
6132 SetChangedFlag (true);
6139 int number
= atoi (function
);
6141 /* correct number */
6143 SetBufferNumber (number
- 1);
6148 notify_crosshair_change (true);
6152 /* --------------------------------------------------------------------------- */
6154 static const char undo_syntax
[] = "Undo()\n"
6157 static const char undo_help
[] = "Undo recent changes.";
6159 /* %start-doc actions Undo
6161 The unlimited undo feature of @code{Pcb} allows you to recover from
6162 most operations that materially affect you work. Calling
6163 @code{Undo()} without any parameter recovers from the last (non-undo)
6164 operation. @code{ClearList} is used to release the allocated
6165 memory. @code{ClearList} is called whenever a new layout is started or
6166 loaded. See also @code{Redo} and @code{Atomic}.
6168 Note that undo groups operations by serial number; changes with the
6169 same serial number will be undone (or redone) as a group. See
6175 ActionUndo (int argc
, char **argv
, Coord x
, Coord y
)
6177 char *function
= ARG (0);
6178 if (!function
|| !*function
)
6180 /* don't allow undo in the middle of an operation */
6181 if (Settings
.Mode
!= POLYGONHOLE_MODE
&&
6182 Crosshair
.AttachedObject
.State
!= STATE_FIRST
)
6184 if (Crosshair
.AttachedBox
.State
!= STATE_FIRST
6185 && Settings
.Mode
!= ARC_MODE
)
6187 /* undo the last operation */
6189 notify_crosshair_change (false);
6190 if ((Settings
.Mode
== POLYGON_MODE
||
6191 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6192 Crosshair
.AttachedPolygon
.PointN
)
6194 GoToPreviousPoint ();
6195 notify_crosshair_change (true);
6198 /* move anchor point if undoing during line creation */
6199 if (Settings
.Mode
== LINE_MODE
)
6201 if (Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6203 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6204 Undo (true); /* undo the connection find */
6205 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
6206 SetLocalRef (0, 0, false);
6207 notify_crosshair_change (true);
6210 if (Crosshair
.AttachedLine
.State
== STATE_THIRD
)
6213 void *ptr1
, *ptr3
, *ptrtmp
;
6215 /* this search is guaranteed to succeed */
6216 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6218 Crosshair
.AttachedLine
.Point1
.X
,
6219 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6220 ptr2
= (LineType
*) ptrtmp
;
6222 /* save both ends of line */
6223 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point1
.X
;
6224 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point1
.Y
;
6225 if ((type
= Undo (true)))
6226 SetChangedFlag (true);
6227 /* check that the undo was of the right type */
6228 if ((type
& UNDO_CREATE
) == 0)
6230 /* wrong undo type, restore anchor points */
6231 Crosshair
.AttachedLine
.Point2
.X
=
6232 Crosshair
.AttachedLine
.Point1
.X
;
6233 Crosshair
.AttachedLine
.Point2
.Y
=
6234 Crosshair
.AttachedLine
.Point1
.Y
;
6235 notify_crosshair_change (true);
6238 /* move to new anchor */
6239 Crosshair
.AttachedLine
.Point1
.X
=
6240 Crosshair
.AttachedLine
.Point2
.X
;
6241 Crosshair
.AttachedLine
.Point1
.Y
=
6242 Crosshair
.AttachedLine
.Point2
.Y
;
6243 /* check if an intermediate point was removed */
6244 if (type
& UNDO_REMOVE
)
6246 /* this search should find the restored line */
6247 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6250 Crosshair
.AttachedLine
.Point2
.X
,
6251 Crosshair
.AttachedLine
.Point2
.Y
, 0);
6252 ptr2
= (LineType
*) ptrtmp
;
6253 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6255 /* undo loses FOUNDFLAG */
6256 SET_FLAG(FOUNDFLAG
, ptr2
);
6257 DrawLine (CURRENT
, ptr2
);
6259 Crosshair
.AttachedLine
.Point1
.X
=
6260 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point2
.X
;
6261 Crosshair
.AttachedLine
.Point1
.Y
=
6262 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point2
.Y
;
6264 FitCrosshairIntoGrid (Crosshair
.X
, Crosshair
.Y
);
6265 AdjustAttachedObjects ();
6266 if (--addedLines
== 0)
6268 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
6269 lastLayer
= CURRENT
;
6273 /* this search is guaranteed to succeed too */
6274 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6277 Crosshair
.AttachedLine
.Point1
.X
,
6278 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6279 ptr2
= (LineType
*) ptrtmp
;
6280 lastLayer
= (LayerType
*) ptr1
;
6282 notify_crosshair_change (true);
6286 if (Settings
.Mode
== ARC_MODE
)
6288 if (Crosshair
.AttachedBox
.State
== STATE_SECOND
)
6290 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
6291 notify_crosshair_change (true);
6294 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
)
6296 void *ptr1
, *ptr2
, *ptr3
;
6298 /* guaranteed to succeed */
6299 SearchObjectByLocation (ARC_TYPE
, &ptr1
, &ptr2
, &ptr3
,
6300 Crosshair
.AttachedBox
.Point1
.X
,
6301 Crosshair
.AttachedBox
.Point1
.Y
, 0);
6302 bx
= GetArcEnds ((ArcType
*) ptr2
);
6303 Crosshair
.AttachedBox
.Point1
.X
=
6304 Crosshair
.AttachedBox
.Point2
.X
= bx
->X1
;
6305 Crosshair
.AttachedBox
.Point1
.Y
=
6306 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y1
;
6307 AdjustAttachedObjects ();
6308 if (--addedLines
== 0)
6309 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
6312 /* undo the last destructive operation */
6314 SetChangedFlag (true);
6318 switch (GetFunctionID (function
))
6320 /* clear 'undo objects' list */
6322 ClearUndoList (false);
6326 notify_crosshair_change (true);
6330 /* --------------------------------------------------------------------------- */
6332 static const char redo_syntax
[] = "Redo()";
6334 static const char redo_help
[] = "Redo recent \"undo\" operations.";
6336 /* %start-doc actions Redo
6338 This routine allows you to recover from the last undo command. You
6339 might want to do this if you thought that undo was going to revert
6340 something other than what it actually did (in case you are confused
6341 about which operations are un-doable), or if you have been backing up
6342 through a long undo list and over-shoot your stopping point. Any
6343 change that is made since the undo in question will trim the redo
6344 list. For example if you add ten lines, then undo three of them you
6345 could use redo to put them back, but if you move a line on the board
6346 before performing the redo, you will lose the ability to "redo" the
6347 three "undone" lines.
6352 ActionRedo (int argc
, char **argv
, Coord x
, Coord y
)
6354 if (((Settings
.Mode
== POLYGON_MODE
||
6355 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6356 Crosshair
.AttachedPolygon
.PointN
) ||
6357 Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6359 notify_crosshair_change (false);
6362 SetChangedFlag (true);
6363 if (Settings
.Mode
== LINE_MODE
&&
6364 Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
6366 LineType
*line
= g_list_last (CURRENT
->Line
)->data
;
6367 Crosshair
.AttachedLine
.Point1
.X
=
6368 Crosshair
.AttachedLine
.Point2
.X
= line
->Point2
.X
;
6369 Crosshair
.AttachedLine
.Point1
.Y
=
6370 Crosshair
.AttachedLine
.Point2
.Y
= line
->Point2
.Y
;
6374 notify_crosshair_change (true);
6378 /* --------------------------------------------------------------------------- */
6380 static const char polygon_syntax
[] = "Polygon(Close|PreviousPoint)";
6382 static const char polygon_help
[] = "Some polygon related stuff.";
6384 /* %start-doc actions Polygon
6386 Polygons need a special action routine to make life easier.
6391 Creates the final segment of the polygon. This may fail if clipping
6392 to 45 degree lines is switched on, in which case a warning is issued.
6395 Resets the newly entered corner to the previous one. The Undo action
6396 will call Polygon(PreviousPoint) when appropriate to do so.
6403 ActionPolygon (int argc
, char **argv
, Coord x
, Coord y
)
6405 char *function
= ARG (0);
6406 if (function
&& Settings
.Mode
== POLYGON_MODE
)
6408 notify_crosshair_change (false);
6409 switch (GetFunctionID (function
))
6411 /* close open polygon if possible */
6416 /* go back to the previous point */
6417 case F_PreviousPoint
:
6418 GoToPreviousPoint ();
6421 notify_crosshair_change (true);
6426 /* --------------------------------------------------------------------------- */
6428 static const char routestyle_syntax
[] = "RouteStyle(1|2|3|4)";
6430 static const char routestyle_help
[] =
6431 "Copies the indicated routing style into the current sizes.";
6433 /* %start-doc actions RouteStyle
6438 ActionRouteStyle (int argc
, char **argv
, Coord x
, Coord y
)
6440 char *str
= ARG (0);
6441 RouteStyleType
*rts
;
6446 number
= atoi (str
);
6447 if (number
> 0 && number
<= NUM_STYLES
)
6449 rts
= &PCB
->RouteStyle
[number
- 1];
6450 SetLineSize (rts
->Thick
);
6451 SetViaSize (rts
->Diameter
, true);
6452 SetViaDrillingHole (rts
->Hole
, true);
6453 SetKeepawayWidth (rts
->Keepaway
);
6454 hid_action("RouteStylesChanged");
6461 /* --------------------------------------------------------------------------- */
6463 static const char moveobject_syntax
[] = "MoveObject(X,Y,dim)";
6465 static const char moveobject_help
[] = "Moves the object under the crosshair.";
6467 /* %start-doc actions MoveObject
6469 The @code{X} and @code{Y} are treated like @code{delta} is for many
6470 other objects. For each, if it's prefixed by @code{+} or @code{-},
6471 then that amount is relative. Otherwise, it's absolute. Units can be
6472 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
6473 units, currently 1/100 mil.
6478 ActionMoveObject (int argc
, char **argv
, Coord x
, Coord y
)
6480 char *x_str
= ARG (0);
6481 char *y_str
= ARG (1);
6482 char *units
= ARG (2);
6484 bool absolute1
, absolute2
;
6485 void *ptr1
, *ptr2
, *ptr3
;
6488 ny
= GetValue (y_str
, units
, &absolute1
);
6489 nx
= GetValue (x_str
, units
, &absolute2
);
6491 type
= SearchScreen (x
, y
, MOVE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6492 if (type
== NO_TYPE
)
6494 Message (_("Nothing found under crosshair\n"));
6501 Crosshair
.AttachedObject
.RubberbandN
= 0;
6502 if (TEST_FLAG (RUBBERBANDFLAG
, PCB
))
6503 LookupRubberbandLines (type
, ptr1
, ptr2
, ptr3
);
6504 if (type
== ELEMENT_TYPE
)
6505 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
6506 MoveObjectAndRubberband (type
, ptr1
, ptr2
, ptr3
, nx
, ny
);
6507 SetChangedFlag (true);
6511 /* --------------------------------------------------------------------------- */
6513 static const char movetocurrentlayer_syntax
[] =
6514 "MoveToCurrentLayer(Object|SelectedObjects)";
6516 static const char movetocurrentlayer_help
[] =
6517 "Moves objects to the current layer.";
6519 /* %start-doc actions MoveToCurrentLayer
6521 Note that moving an element from a component layer to a solder layer,
6522 or from solder to component, won't automatically flip it. Use the
6523 @code{Flip()} action to do that.
6528 ActionMoveToCurrentLayer (int argc
, char **argv
, Coord x
, Coord y
)
6530 char *function
= ARG (0);
6533 switch (GetFunctionID (function
))
6538 void *ptr1
, *ptr2
, *ptr3
;
6540 gui
->get_coords (_("Select an Object"), &x
, &y
);
6542 SearchScreen (x
, y
, MOVETOLAYER_TYPES
,
6543 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6544 if (MoveObjectToLayer (type
, ptr1
, ptr2
, ptr3
, CURRENT
, false))
6545 SetChangedFlag (true);
6549 case F_SelectedObjects
:
6551 if (MoveSelectedObjectsToLayer (CURRENT
))
6552 SetChangedFlag (true);
6560 static const char setsame_syntax
[] = "SetSame()";
6562 static const char setsame_help
[] =
6563 "Sets current layer and sizes to match indicated item.";
6565 /* %start-doc actions SetSame
6567 When invoked over any line, arc, polygon, or via, this changes the
6568 current layer to be the layer that item is on, and changes the current
6569 sizes (thickness, keepaway, drill, etc) according to that item.
6574 ActionSetSame (int argc
, char **argv
, Coord x
, Coord y
)
6576 void *ptr1
, *ptr2
, *ptr3
;
6578 LayerType
*layer
= CURRENT
;
6580 type
= SearchScreen (x
, y
, CLONE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6581 /* set layer current and size from line or arc */
6585 notify_crosshair_change (false);
6586 Settings
.LineThickness
= ((LineType
*) ptr2
)->Thickness
;
6587 Settings
.Keepaway
= ((LineType
*) ptr2
)->Clearance
/ 2;
6588 layer
= (LayerType
*) ptr1
;
6589 if (Settings
.Mode
!= LINE_MODE
)
6590 SetMode (LINE_MODE
);
6591 notify_crosshair_change (true);
6592 hid_action ("RouteStylesChanged");
6596 notify_crosshair_change (false);
6597 Settings
.LineThickness
= ((ArcType
*) ptr2
)->Thickness
;
6598 Settings
.Keepaway
= ((ArcType
*) ptr2
)->Clearance
/ 2;
6599 layer
= (LayerType
*) ptr1
;
6600 if (Settings
.Mode
!= ARC_MODE
)
6602 notify_crosshair_change (true);
6603 hid_action ("RouteStylesChanged");
6607 layer
= (LayerType
*) ptr1
;
6611 notify_crosshair_change (false);
6612 Settings
.ViaThickness
= ((PinType
*) ptr2
)->Thickness
;
6613 Settings
.ViaDrillingHole
= ((PinType
*) ptr2
)->DrillingHole
;
6614 Settings
.Keepaway
= ((PinType
*) ptr2
)->Clearance
/ 2;
6615 if (Settings
.Mode
!= VIA_MODE
)
6617 notify_crosshair_change (true);
6618 hid_action ("RouteStylesChanged");
6624 if (layer
!= CURRENT
)
6626 ChangeGroupVisibility (GetLayerNumber (PCB
->Data
, layer
), true, true);
6633 /* --------------------------------------------------------------------------- */
6635 static const char setflag_syntax
[] =
6636 "SetFlag(Object|Selected|SelectedObjects, flag)\n"
6637 "SetFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6638 "SetFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6639 "SetFlag(SelectedElements, flag)\n"
6640 "flag = square | octagon | thermal | join";
6642 static const char setflag_help
[] = "Sets flags on objects.";
6644 /* %start-doc actions SetFlag
6646 Turns the given flag on, regardless of its previous setting. See
6650 SetFlag(SelectedPins,thermal)
6656 ActionSetFlag (int argc
, char **argv
, Coord x
, Coord y
)
6658 char *function
= ARG (0);
6659 char *flag
= ARG (1);
6660 ChangeFlag (function
, flag
, 1, "SetFlag");
6664 /* --------------------------------------------------------------------------- */
6666 static const char clrflag_syntax
[] =
6667 "ClrFlag(Object|Selected|SelectedObjects, flag)\n"
6668 "ClrFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6669 "ClrFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6670 "ClrFlag(SelectedElements, flag)\n"
6671 "flag = square | octagon | thermal | join";
6673 static const char clrflag_help
[] = "Clears flags on objects.";
6675 /* %start-doc actions ClrFlag
6677 Turns the given flag off, regardless of its previous setting. See
6681 ClrFlag(SelectedLines,join)
6687 ActionClrFlag (int argc
, char **argv
, Coord x
, Coord y
)
6689 char *function
= ARG (0);
6690 char *flag
= ARG (1);
6691 ChangeFlag (function
, flag
, 0, "ClrFlag");
6695 /* --------------------------------------------------------------------------- */
6697 static const char changeflag_syntax
[] =
6698 "ChangeFlag(Object|Selected|SelectedObjects, flag, value)\n"
6699 "ChangeFlag(SelectedLines|SelectedPins|SelectedVias, flag, value)\n"
6700 "ChangeFlag(SelectedPads|SelectedTexts|SelectedNames, flag, value)\n"
6701 "ChangeFlag(SelectedElements, flag, value)\n"
6702 "flag = square | octagon | thermal | join\n"
6705 static const char changeflag_help
[] = "Sets or clears flags on objects.";
6707 /* %start-doc actions ChangeFlag
6709 Toggles the given flag on the indicated object(s). The flag may be
6710 one of the flags listed above (square, octagon, thermal, join). The
6711 value may be the number 0 or 1. If the value is 0, the flag is
6712 cleared. If the value is 1, the flag is set.
6717 ActionChangeFlag (int argc
, char **argv
, Coord x
, Coord y
)
6719 char *function
= ARG (0);
6720 char *flag
= ARG (1);
6721 int value
= argc
> 2 ? atoi (argv
[2]) : -1;
6722 if (value
!= 0 && value
!= 1)
6725 ChangeFlag (function
, flag
, value
, "ChangeFlag");
6731 ChangeFlag (char *what
, char *flag_name
, int value
, char *cmd_name
)
6733 bool (*set_object
) (int, void *, void *, void *);
6734 bool (*set_selected
) (int);
6736 if (NSTRCMP (flag_name
, "square") == 0)
6738 set_object
= value
? SetObjectSquare
: ClrObjectSquare
;
6739 set_selected
= value
? SetSelectedSquare
: ClrSelectedSquare
;
6741 else if (NSTRCMP (flag_name
, "octagon") == 0)
6743 set_object
= value
? SetObjectOctagon
: ClrObjectOctagon
;
6744 set_selected
= value
? SetSelectedOctagon
: ClrSelectedOctagon
;
6746 else if (NSTRCMP (flag_name
, "join") == 0)
6748 /* Note: these are backwards, because the flag is "clear" but
6749 the command is "join". */
6750 set_object
= value
? ClrObjectJoin
: SetObjectJoin
;
6751 set_selected
= value
? ClrSelectedJoin
: SetSelectedJoin
;
6755 Message (_("%s(): Flag \"%s\" is not valid\n"), cmd_name
, flag_name
);
6759 switch (GetFunctionID (what
))
6764 void *ptr1
, *ptr2
, *ptr3
;
6767 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
6768 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6769 if (TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
6770 Message (_("Sorry, the object is locked\n"));
6771 if (set_object (type
, ptr1
, ptr2
, ptr3
))
6772 SetChangedFlag (true);
6776 case F_SelectedVias
:
6777 if (set_selected (VIA_TYPE
))
6778 SetChangedFlag (true);
6781 case F_SelectedPins
:
6782 if (set_selected (PIN_TYPE
))
6783 SetChangedFlag (true);
6786 case F_SelectedPads
:
6787 if (set_selected (PAD_TYPE
))
6788 SetChangedFlag (true);
6791 case F_SelectedLines
:
6792 if (set_selected (LINE_TYPE
))
6793 SetChangedFlag (true);
6796 case F_SelectedTexts
:
6797 if (set_selected (TEXT_TYPE
))
6798 SetChangedFlag (true);
6801 case F_SelectedNames
:
6802 if (set_selected (ELEMENTNAME_TYPE
))
6803 SetChangedFlag (true);
6806 case F_SelectedElements
:
6807 if (set_selected (ELEMENT_TYPE
))
6808 SetChangedFlag (true);
6812 case F_SelectedObjects
:
6813 if (set_selected (CHANGESIZE_TYPES
))
6814 SetChangedFlag (true);
6819 /* --------------------------------------------------------------------------- */
6821 static const char executefile_syntax
[] = "ExecuteFile(filename)";
6823 static const char executefile_help
[] = "Run actions from the given file.";
6825 /* %start-doc actions ExecuteFile
6827 Lines starting with @code{#} are ignored.
6832 ActionExecuteFile (int argc
, char **argv
, Coord x
, Coord y
)
6841 AFAIL (executefile
);
6845 if ((fp
= fopen (fname
, "r")) == NULL
)
6847 fprintf (stderr
, _("Could not open actions file \"%s\".\n"), fname
);
6852 defer_needs_update
= 0;
6853 while (fgets (line
, sizeof (line
), fp
) != NULL
)
6858 /* eat the trailing newline */
6859 while (*sp
&& *sp
!= '\r' && *sp
!= '\n')
6863 /* eat leading spaces and tabs */
6865 while (*sp
&& (*sp
== ' ' || *sp
== '\t'))
6869 * if we have anything left and its not a comment line
6873 if (*sp
&& *sp
!= '#')
6875 /*Message ("%s : line %-3d : \"%s\"\n", fname, n, sp);*/
6876 hid_parse_actions (sp
);
6881 if (defer_needs_update
)
6883 IncrementUndoSerialNumber ();
6884 gui
->invalidate_all ();
6890 /* --------------------------------------------------------------------------- */
6893 ActionPSCalib (int argc
, char **argv
, Coord x
, Coord y
)
6895 HID
*ps
= hid_find_exporter ("ps");
6896 ps
->calibrate (0.0,0.0);
6900 /* --------------------------------------------------------------------------- */
6902 static ElementType
*element_cache
= NULL
;
6904 static ElementType
*
6905 find_element_by_refdes (char *refdes
)
6908 && NAMEONPCB_NAME(element_cache
)
6909 && strcmp (NAMEONPCB_NAME(element_cache
), refdes
) == 0)
6910 return element_cache
;
6912 ELEMENT_LOOP (PCB
->Data
);
6914 if (NAMEONPCB_NAME(element
)
6915 && strcmp (NAMEONPCB_NAME(element
), refdes
) == 0)
6917 element_cache
= element
;
6918 return element_cache
;
6925 static AttributeType
*
6926 lookup_attr (AttributeListType
*list
, const char *name
)
6929 for (i
=0; i
<list
->Number
; i
++)
6930 if (strcmp (list
->List
[i
].name
, name
) == 0)
6931 return & list
->List
[i
];
6936 delete_attr (AttributeListType
*list
, AttributeType
*attr
)
6938 int idx
= attr
- list
->List
;
6939 if (idx
< 0 || idx
>= list
->Number
)
6941 if (list
->Number
- idx
> 1)
6942 memmove (attr
, attr
+1, (list
->Number
- idx
- 1) * sizeof(AttributeType
));
6946 /* ---------------------------------------------------------------- */
6947 static const char elementlist_syntax
[] = "ElementList(Start|Done|Need,<refdes>,<footprint>,<value>)";
6949 static const char elementlist_help
[] = "Adds the given element if it doesn't already exist.";
6951 /* %start-doc actions elementlist
6956 Indicates the start of an element list; call this before any Need
6960 Searches the board for an element with a matching refdes.
6962 If found, the value and footprint are updated.
6964 If not found, a new element is created with the given footprint and value.
6967 Compares the list of elements needed since the most recent
6968 @code{start} with the list of elements actually on the board. Any
6969 elements that weren't listed are selected, so that the user may delete
6976 static int number_of_footprints_not_found
;
6979 parse_layout_attribute_units (char *name
, int def
)
6981 const char *as
= AttributeGet (PCB
, name
);
6984 return GetValue (as
, NULL
, NULL
);
6988 ActionElementList (int argc
, char **argv
, Coord x
, Coord y
)
6990 ElementType
*e
= NULL
;
6991 char *refdes
, *value
, *footprint
, *old
;
6993 char *function
= argv
[0];
6996 printf("Entered ActionElementList, executing function %s\n", function
);
6999 if (strcasecmp (function
, "start") == 0)
7001 ELEMENT_LOOP (PCB
->Data
);
7003 CLEAR_FLAG (FOUNDFLAG
, element
);
7006 element_cache
= NULL
;
7007 number_of_footprints_not_found
= 0;
7011 if (strcasecmp (function
, "done") == 0)
7013 ELEMENT_LOOP (PCB
->Data
);
7015 if (TEST_FLAG (FOUNDFLAG
, element
))
7017 CLEAR_FLAG (FOUNDFLAG
, element
);
7019 else if (! EMPTY_STRING_P (NAMEONPCB_NAME (element
)))
7021 /* Unnamed elements should remain untouched */
7022 SET_FLAG (SELECTEDFLAG
, element
);
7026 if (number_of_footprints_not_found
> 0)
7027 gui
->confirm_dialog ("Not all requested footprints were found.\n"
7028 "See the message log for details",
7033 if (strcasecmp (function
, "need") != 0)
7034 AFAIL (elementlist
);
7037 AFAIL (elementlist
);
7046 args
[0] = footprint
;
7051 printf(" ... footprint = %s\n", footprint
);
7052 printf(" ... refdes = %s\n", refdes
);
7053 printf(" ... value = %s\n", value
);
7056 e
= find_element_by_refdes (refdes
);
7063 printf(" ... Footprint not on board, need to add it.\n");
7065 /* Not on board, need to add it. */
7066 if (LoadFootprint(argc
, args
, x
, y
))
7068 number_of_footprints_not_found
++;
7072 nx
= PCB
->MaxWidth
/ 2;
7073 ny
= PCB
->MaxHeight
/ 2;
7074 d
= MIN (PCB
->MaxWidth
, PCB
->MaxHeight
) / 10;
7076 nx
= parse_layout_attribute_units ("import::newX", nx
);
7077 ny
= parse_layout_attribute_units ("import::newY", ny
);
7078 d
= parse_layout_attribute_units ("import::disperse", d
);
7082 nx
+= rand () % (d
*2) - d
;
7083 ny
+= rand () % (d
*2) - d
;
7088 if (nx
>= PCB
->MaxWidth
)
7089 nx
= PCB
->MaxWidth
- 1;
7092 if (ny
>= PCB
->MaxHeight
)
7093 ny
= PCB
->MaxHeight
- 1;
7095 /* Place components onto center of board. */
7096 if (CopyPastebufferToLayout (nx
, ny
))
7097 SetChangedFlag (true);
7100 else if (e
&& strcmp (DESCRIPTION_NAME(e
), footprint
) != 0)
7103 printf(" ... Footprint on board, but different from footprint loaded.\n");
7109 /* Different footprint, we need to swap them out. */
7110 if (LoadFootprint(argc
, args
, x
, y
))
7112 number_of_footprints_not_found
++;
7116 er
= ElementOrientation (e
);
7117 pe
= PASTEBUFFER
->Data
->Element
->data
;
7119 MirrorElementCoordinates (PASTEBUFFER
->Data
, pe
, pe
->MarkY
*2 - PCB
->MaxHeight
);
7120 pr
= ElementOrientation (pe
);
7126 RotateElementLowLevel (PASTEBUFFER
->Data
, pe
, pe
->MarkX
, pe
->MarkY
, (er
-pr
+4)%4);
7128 for (i
=0; i
<MAX_ELEMENTNAMES
; i
++)
7130 pe
->Name
[i
].X
= e
->Name
[i
].X
- mx
+ pe
->MarkX
;
7131 pe
->Name
[i
].Y
= e
->Name
[i
].Y
- my
+ pe
->MarkY
;
7132 pe
->Name
[i
].Direction
= e
->Name
[i
].Direction
;
7133 pe
->Name
[i
].Scale
= e
->Name
[i
].Scale
;
7138 if (CopyPastebufferToLayout (mx
, my
))
7139 SetChangedFlag (true);
7142 /* Now reload footprint */
7143 element_cache
= NULL
;
7144 e
= find_element_by_refdes (refdes
);
7146 old
= ChangeElementText (PCB
, PCB
->Data
, e
, NAMEONPCB_INDEX
, strdup (refdes
));
7149 old
= ChangeElementText (PCB
, PCB
->Data
, e
, VALUE_INDEX
, strdup (value
));
7153 SET_FLAG (FOUNDFLAG
, e
);
7156 printf(" ... Leaving ActionElementList.\n");
7162 /* ---------------------------------------------------------------- */
7163 static const char elementsetattr_syntax
[] = "ElementSetAttr(refdes,name[,value])";
7165 static const char elementsetattr_help
[] = "Sets or clears an element-specific attribute.";
7167 /* %start-doc actions elementsetattr
7169 If a value is specified, the named attribute is added (if not already
7170 present) or changed (if it is) to the given value. If the value is
7171 not specified, the given attribute is removed if present.
7176 ActionElementSetAttr (int argc
, char **argv
, Coord x
, Coord y
)
7178 ElementType
*e
= NULL
;
7179 char *refdes
, *name
, *value
;
7180 AttributeType
*attr
;
7184 AFAIL (changepinname
);
7191 ELEMENT_LOOP (PCB
->Data
);
7193 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
7203 Message(_("Cannot change attribute of %s - element not found\n"), refdes
);
7207 attr
= lookup_attr (&e
->Attributes
, name
);
7212 attr
->value
= strdup (value
);
7214 if (attr
&& ! value
)
7216 delete_attr (& e
->Attributes
, attr
);
7220 CreateNewAttribute (& e
->Attributes
, name
, value
);
7226 /* ---------------------------------------------------------------- */
7227 static const char execcommand_syntax
[] = "ExecCommand(command)";
7229 static const char execcommand_help
[] = "Runs a command.";
7231 /* %start-doc actions execcommand
7233 Runs the given command, which is a system executable.
7238 ActionExecCommand (int argc
, char **argv
, Coord x
, Coord y
)
7244 AFAIL (execcommand
);
7249 if (system (command
))
7254 /* ---------------------------------------------------------------- */
7257 pcb_spawnvp (char **argv
)
7259 #ifdef HAVE__SPAWNVP
7260 int result
= _spawnvp (_P_WAIT
, argv
[0], (const char * const *) argv
);
7271 Message(_("Cannot fork!"));
7277 execvp (argv
[0], argv
);
7290 /* ---------------------------------------------------------------- */
7292 * Creates a new temporary file name. Hopefully the operating system
7293 * provides a mkdtemp() function to securily create a temporary
7294 * directory with mode 0700. If so then that directory is created and
7295 * the returned string is made up of the directory plus the name
7296 * variable. For example:
7298 * tempfile_name_new ("myfile") might return
7299 * "/var/tmp/pcb.123456/myfile".
7301 * If mkdtemp() is not available then 'name' is ignored and the
7302 * insecure tmpnam() function is used.
7304 * Files/names created with tempfile_name_new() should be unlinked
7305 * with tempfile_unlink to make sure the temporary directory is also
7306 * removed when mkdtemp() is used.
7309 tempfile_name_new (char * name
)
7311 char *tmpfile
= NULL
;
7313 char *tmpdir
, *mytmpdir
;
7317 assert ( name
!= NULL
);
7320 #define TEMPLATE "pcb.XXXXXXXX"
7323 tmpdir
= getenv ("TMPDIR");
7325 /* FIXME -- what about win32? */
7326 if (tmpdir
== NULL
) {
7330 mytmpdir
= (char *) malloc (sizeof(char) *
7335 if (mytmpdir
== NULL
) {
7336 fprintf (stderr
, "%s(): malloc failed()\n", __FUNCTION__
);
7341 (void)strcat (mytmpdir
, tmpdir
);
7342 (void)strcat (mytmpdir
, PCB_DIR_SEPARATOR_S
);
7343 (void)strcat (mytmpdir
, TEMPLATE
);
7344 if (mkdtemp (mytmpdir
) == NULL
) {
7345 fprintf (stderr
, "%s(): mkdtemp (\"%s\") failed\n", __FUNCTION__
, mytmpdir
);
7351 len
= strlen (mytmpdir
) + /* the temp directory name */
7352 1 + /* the directory sep. */
7353 strlen (name
) + /* the file name */
7354 1 /* the \0 termination */
7357 tmpfile
= (char *) malloc (sizeof (char) * len
);
7360 (void)strcat (tmpfile
, mytmpdir
);
7361 (void)strcat (tmpfile
, PCB_DIR_SEPARATOR_S
);
7362 (void)strcat (tmpfile
, name
);
7368 * tmpnam() uses a static buffer so strdup() the result right away
7369 * in case someone decides to create multiple temp names.
7371 tmpfile
= strdup (tmpnam (NULL
));
7374 /* Guile doesn't like \ separators */
7376 for (c
= tmpfile
; *c
; c
++)
7386 /* ---------------------------------------------------------------- */
7388 * Unlink a temporary file. If we have mkdtemp() then our temp file
7389 * lives in a temporary directory and we need to remove that directory
7393 tempfile_unlink (char * name
)
7396 /* SDB says: Want to keep old temp files for examiniation when debugging */
7405 /* it is possible that the file was never created so it is OK if the
7408 /* now figure out the directory name to remove */
7409 e
= strlen (name
) - 1;
7410 while (e
> 0 && name
[e
] != PCB_DIR_SEPARATOR_C
) {e
--;}
7412 dname
= strdup (name
);
7416 * at this point, e *should* point to the end of the directory part
7417 * but lets make sure.
7420 rc2
= rmdir (dname
);
7426 fprintf (stderr
, _("%s(): Unable to determine temp directory name from the temp file\n"),
7428 fprintf (stderr
, "%s(): \"%s\"\n",
7429 __FUNCTION__
, name
);
7433 /* name was allocated with malloc */
7438 * FIXME - should also return -1 if the temp file exists and was not
7446 int rc
= unlink (name
);
7449 fprintf (stderr
, _("Failed to unlink \"%s\"\n"), name
);
7460 /* ---------------------------------------------------------------- */
7461 static const char import_syntax
[] =
7463 "Import([gnetlist|make[,source,source,...]])\n"
7464 "Import(setnewpoint[,(mark|center|X,Y)])\n"
7465 "Import(setdisperse,D,units)\n";
7467 static const char import_help
[] = "Import schematics.";
7469 /* %start-doc actions Import
7471 Imports element and netlist data from the schematics (or some other
7472 source). The first parameter, which is optional, is the mode. If not
7473 specified, the @code{import::mode} attribute in the PCB is used.
7474 @code{gnetlist} means gnetlist is used to obtain the information from
7475 the schematics. @code{make} invokes @code{make}, assuming the user
7476 has a @code{Makefile} in the current directory. The @code{Makefile}
7477 will be invoked with the following variables set:
7482 The name of the .pcb file
7485 A space-separated list of source files
7488 The name of the file in which to put the command script, which may
7489 contain any @pcb{} actions. By default, this is a temporary file
7490 selected by @pcb{}, but if you specify an @code{import::outfile}
7491 attribute, that file name is used instead (and not automatically
7492 deleted afterwards).
7496 The target specified to be built is the first of these that apply:
7501 The target specified by an @code{import::target} attribute.
7504 The output file specified by an @code{import::outfile} attribute.
7507 If nothing else is specified, the target is @code{pcb_import}.
7511 If you specify an @code{import::makefile} attribute, then "-f <that
7512 file>" will be added to the command line.
7514 If you specify the mode, you may also specify the source files
7515 (schematics). If you do not specify any, the list of schematics is
7516 obtained by reading the @code{import::src@var{N}} attributes (like
7517 @code{import::src0}, @code{import::src1}, etc).
7519 For compatibility with future extensions to the import file format,
7520 the generated file @emph{must not} start with the two characters
7523 If a temporary file is needed the @code{TMPDIR} environment variable
7524 is used to select its location.
7526 Note that the programs @code{gnetlist} and @code{make} may be
7527 overridden by the user via the @code{make-program} and @code{gnetlist}
7528 @code{pcb} settings (i.e. in @code{~/.pcb/settings} or on the command
7531 If @pcb{} cannot determine which schematic(s) to import from, the GUI
7532 is called to let user choose (see @code{ImportGUI()}).
7534 Note that Import() doesn't delete anything - after an Import, elements
7535 which shouldn't be on the board are selected and may be removed once
7536 it's determined that the deletion is appropriate.
7538 If @code{Import()} is called with @code{setnewpoint}, then the location
7539 of new components can be specified. This is where parts show up when
7540 they're added to the board. The default is the center of the board.
7544 @item Import(setnewpoint)
7546 Prompts the user to click on the board somewhere, uses that point. If
7547 called by a hotkey, uses the current location of the crosshair.
7549 @item Import(setnewpoint,mark)
7551 Uses the location of the mark. If no mark is present, the point is
7554 @item Import(setnewpoint,center)
7556 Resets the point to the center of the board.
7558 @item Import(setnewpoint,X,Y,units)
7560 Sets the point to the specific coordinates given. Example:
7561 @code{Import(setnewpoint,50,25,mm)}
7565 Note that the X and Y locations are stored in attributes named
7566 @code{import::newX} and @code{import::newY} so you could change them
7567 manually if you wished.
7569 Calling @code{Import(setdisperse,D,units)} sets how much the newly
7570 placed elements are dispersed relative to the set point. For example,
7571 @code{Import(setdisperse,10,mm)} will offset each part randomly up to
7572 10mm away from the point. The default dispersion is 1/10th of the
7573 smallest board dimension. Dispersion is saved in the
7574 @code{import::disperse} attribute.
7579 ActionImport (int argc
, char **argv
, Coord x
, Coord y
)
7582 char **sources
= NULL
;
7586 printf("ActionImport: =========== Entering ActionImport ============\n");
7591 if (mode
&& strcasecmp (mode
, "setdisperse") == 0)
7600 const char *as
= AttributeGet (PCB
, "import::disperse");
7601 ds
= gui
->prompt_for(_("Enter dispersion:"), as
? as
: "0");
7605 sprintf(buf
, "%s%s", ds
, units
);
7606 AttributePut (PCB
, "import::disperse", buf
);
7609 AttributePut (PCB
, "import::disperse", ds
);
7610 if (ARG (1) == NULL
)
7615 if (mode
&& strcasecmp (mode
, "setnewpoint") == 0)
7617 const char *xs
, *ys
, *units
;
7627 gui
->get_coords (_("Click on a location"), &x
, &y
);
7629 else if (strcasecmp (xs
, "center") == 0)
7631 AttributeRemove (PCB
, "import::newX");
7632 AttributeRemove (PCB
, "import::newY");
7635 else if (strcasecmp (xs
, "mark") == 0)
7645 x
= GetValue (xs
, units
, NULL
);
7646 y
= GetValue (ys
, units
, NULL
);
7650 Message (_("Bad syntax for Import(setnewpoint)"));
7654 pcb_sprintf (buf
, "%$ms", x
);
7655 AttributePut (PCB
, "import::newX", buf
);
7656 pcb_sprintf (buf
, "%$ms", y
);
7657 AttributePut (PCB
, "import::newY", buf
);
7662 mode
= AttributeGet (PCB
, "import::mode");
7669 nsources
= argc
- 1;
7680 sprintf(sname
, "import::src%d", nsources
);
7681 src
= AttributeGet (PCB
, sname
);
7686 sources
= (char **) malloc ((nsources
+ 1) * sizeof (char *));
7690 sprintf(sname
, "import::src%d", nsources
);
7691 src
= AttributeGet (PCB
, sname
);
7692 sources
[nsources
] = src
;
7699 /* Replace .pcb with .sch and hope for the best. */
7700 char *pcbname
= PCB
->Filename
;
7702 char *dot
, *slash
, *bslash
;
7705 return hid_action("ImportGUI");
7707 schname
= (char *) malloc (strlen(pcbname
) + 5);
7708 strcpy (schname
, pcbname
);
7709 dot
= strchr (schname
, '.');
7710 slash
= strchr (schname
, '/');
7711 bslash
= strchr (schname
, '\\');
7712 if (dot
&& slash
&& dot
< slash
)
7714 if (dot
&& bslash
&& dot
< bslash
)
7718 strcat (schname
, ".sch");
7720 if (access (schname
, F_OK
))
7723 return hid_action("ImportGUI");
7726 sources
= (char **) malloc (2 * sizeof (char *));
7727 sources
[0] = schname
;
7732 if (strcasecmp (mode
, "gnetlist") == 0)
7734 char *tmpfile
= tempfile_name_new ("gnetlist_output");
7738 if (tmpfile
== NULL
) {
7739 Message (_("Could not create temp file"));
7743 cmd
= (char **) malloc ((7 + nsources
) * sizeof (char *));
7744 cmd
[0] = Settings
.GnetlistProgram
;
7750 for (i
=0; i
<nsources
; i
++)
7751 cmd
[6+i
] = sources
[i
];
7752 cmd
[6+nsources
] = NULL
;
7755 printf("ActionImport: =========== About to run gnetlist ============\n");
7756 printf("%s %s %s %s %s %s %s ...\n",
7757 cmd
[0], cmd
[1], cmd
[2], cmd
[3], cmd
[4], cmd
[5], cmd
[6]);
7760 if (pcb_spawnvp (cmd
))
7767 printf("ActionImport: =========== About to run ActionExecuteFile, file = %s ============\n", tmpfile
);
7772 ActionExecuteFile (1, cmd
, 0, 0);
7775 tempfile_unlink (tmpfile
);
7777 else if (strcasecmp (mode
, "make") == 0)
7779 int must_free_tmpfile
= 0;
7785 char *user_outfile
= NULL
;
7786 char *user_makefile
= NULL
;
7787 char *user_target
= NULL
;
7790 user_outfile
= AttributeGet (PCB
, "import::outfile");
7791 user_makefile
= AttributeGet (PCB
, "import::makefile");
7792 user_target
= AttributeGet (PCB
, "import::target");
7793 if (user_outfile
&& !user_target
)
7794 user_target
= user_outfile
;
7797 tmpfile
= user_outfile
;
7800 tmpfile
= tempfile_name_new ("gnetlist_output");
7801 if (tmpfile
== NULL
) {
7802 Message (_("Could not create temp file"));
7805 must_free_tmpfile
= 1;
7808 srclen
= sizeof("SRCLIST=") + 2;
7809 for (i
=0; i
<nsources
; i
++)
7810 srclen
+= strlen (sources
[i
]) + 2;
7811 srclist
= (char *) malloc (srclen
);
7812 strcpy (srclist
, "SRCLIST=");
7813 for (i
=0; i
<nsources
; i
++)
7816 strcat (srclist
, " ");
7817 strcat (srclist
, sources
[i
]);
7820 cmd
[0] = Settings
.MakeProgram
;
7822 cmd
[2] = Concat ("PCB=", PCB
->Filename
, NULL
);
7824 cmd
[4] = Concat ("OUT=", tmpfile
, NULL
);
7829 cmd
[i
++] = user_makefile
;
7831 cmd
[i
++] = user_target
? user_target
: (char *)"pcb_import";
7834 if (pcb_spawnvp (cmd
))
7836 if (must_free_tmpfile
)
7846 ActionExecuteFile (1, cmd
, 0, 0);
7851 if (must_free_tmpfile
)
7852 tempfile_unlink (tmpfile
);
7856 Message (_("Unknown import mode: %s\n"), mode
);
7861 AddAllRats (false, NULL
);
7864 printf("ActionImport: =========== Leaving ActionImport ============\n");
7870 /* ------------------------------------------------------------ */
7872 static const char attributes_syntax
[] =
7873 "Attributes(Layout|Layer|Element)\n"
7874 "Attributes(Layer,layername)";
7876 static const char attributes_help
[] =
7877 "Let the user edit the attributes of the layout, current or given\n"
7878 "layer, or selected element.";
7880 /* %start-doc actions Attributes
7882 This just pops up a dialog letting the user edit the attributes of the
7883 pcb, an element, or a layer.
7889 ActionAttributes (int argc
, char **argv
, Coord x
, Coord y
)
7891 char *function
= ARG (0);
7892 char *layername
= ARG (1);
7898 if (!gui
->edit_attributes
)
7900 Message (_("This GUI doesn't support Attribute Editing\n"));
7904 switch (GetFunctionID (function
))
7908 gui
->edit_attributes("Layout Attributes", &(PCB
->Attributes
));
7914 LayerType
*layer
= CURRENT
;
7919 for (i
=0; i
<max_copper_layer
; i
++)
7920 if (strcmp (PCB
->Data
->Layer
[i
].Name
, layername
) == 0)
7922 layer
= & (PCB
->Data
->Layer
[i
]);
7927 Message (_("No layer named %s\n"), layername
);
7931 buf
= (char *) malloc (strlen (layer
->Name
) + strlen ("Layer X Attributes"));
7932 sprintf (buf
, "Layer %s Attributes", layer
->Name
);
7933 gui
->edit_attributes(buf
, &(layer
->Attributes
));
7941 ElementType
*e
= NULL
;
7942 ELEMENT_LOOP (PCB
->Data
);
7944 if (TEST_FLAG (SELECTEDFLAG
, element
))
7953 Message (_("Too many elements selected\n"));
7959 gui
->get_coords (_("Click on an element"), &x
, &y
);
7961 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
7962 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
7963 e
= (ElementType
*) ptrtmp
;
7966 Message (_("No element found there\n"));
7971 if (NAMEONPCB_NAME(e
))
7973 buf
= (char *) malloc (strlen (NAMEONPCB_NAME(e
)) + strlen ("Element X Attributes"));
7974 sprintf(buf
, "Element %s Attributes", NAMEONPCB_NAME(e
));
7978 buf
= strdup ("Unnamed Element Attributes");
7980 gui
->edit_attributes(buf
, &(e
->Attributes
));
7992 /* --------------------------------------------------------------------------- */
7994 HID_Action action_action_list
[] = {
7995 {"AddRats", 0, ActionAddRats
,
7996 addrats_help
, addrats_syntax
}
7998 {"Attributes", 0, ActionAttributes
,
7999 attributes_help
, attributes_syntax
}
8001 {"Atomic", 0, ActionAtomic
,
8002 atomic_help
, atomic_syntax
}
8004 {"AutoPlaceSelected", 0, ActionAutoPlaceSelected
,
8005 autoplace_help
, autoplace_syntax
}
8007 {"AutoRoute", 0, ActionAutoRoute
,
8008 autoroute_help
, autoroute_syntax
}
8010 {"ChangeClearSize", 0, ActionChangeClearSize
,
8011 changeclearsize_help
, changeclearsize_syntax
}
8013 {"ChangeDrillSize", 0, ActionChange2ndSize
,
8014 changedrillsize_help
, changedrillsize_syntax
}
8016 {"ChangeHole", 0, ActionChangeHole
,
8017 changehold_help
, changehold_syntax
}
8019 {"ChangeJoin", 0, ActionChangeJoin
,
8020 changejoin_help
, changejoin_syntax
}
8022 {"ChangeName", 0, ActionChangeName
,
8023 changename_help
, changename_syntax
}
8025 {"ChangePaste", 0, ActionChangePaste
,
8026 changepaste_help
, changepaste_syntax
}
8028 {"ChangePinName", 0, ActionChangePinName
,
8029 changepinname_help
, changepinname_syntax
}
8031 {"ChangeSize", 0, ActionChangeSize
,
8032 changesize_help
, changesize_syntax
}
8034 {"ChangeSquare", 0, ActionChangeSquare
,
8035 changesquare_help
, changesquare_syntax
}
8037 {"ChangeOctagon", 0, ActionChangeOctagon
,
8038 changeoctagon_help
, changeoctagon_syntax
}
8040 {"ClearSquare", 0, ActionClearSquare
,
8041 clearsquare_help
, clearsquare_syntax
}
8043 {"ClearOctagon", 0, ActionClearOctagon
,
8044 clearoctagon_help
, clearoctagon_syntax
}
8046 {"Connection", 0, ActionConnection
,
8047 connection_help
, connection_syntax
}
8049 {"Delete", 0, ActionDelete
,
8050 delete_help
, delete_syntax
}
8052 {"DeleteRats", 0, ActionDeleteRats
,
8053 deleterats_help
, deleterats_syntax
}
8055 {"DisperseElements", 0, ActionDisperseElements
,
8056 disperseelements_help
, disperseelements_syntax
}
8058 {"Display", 0, ActionDisplay
,
8059 display_help
, display_syntax
}
8061 {"DRC", 0, ActionDRCheck
,
8062 drc_help
, drc_syntax
}
8064 {"DumpLibrary", 0, ActionDumpLibrary
,
8065 dumplibrary_help
, dumplibrary_syntax
}
8067 {"ExecuteFile", 0, ActionExecuteFile
,
8068 executefile_help
, executefile_syntax
}
8070 {"Flip", N_("Click on Object or Flip Point"), ActionFlip
,
8071 flip_help
, flip_syntax
}
8073 {"LoadFrom", 0, ActionLoadFrom
,
8074 loadfrom_help
, loadfrom_syntax
}
8076 {"MarkCrosshair", 0, ActionMarkCrosshair
,
8077 markcrosshair_help
, markcrosshair_syntax
}
8079 {"Message", 0, ActionMessage
,
8080 message_help
, message_syntax
}
8082 {"MinMaskGap", 0, ActionMinMaskGap
,
8083 minmaskgap_help
, minmaskgap_syntax
}
8085 {"MinClearGap", 0, ActionMinClearGap
,
8086 mincleargap_help
, mincleargap_syntax
}
8088 {"Mode", 0, ActionMode
,
8089 mode_help
, mode_syntax
}
8091 {"MorphPolygon", 0, ActionMorphPolygon
,
8092 morphpolygon_help
, morphpolygon_syntax
}
8094 {"PasteBuffer", 0, ActionPasteBuffer
,
8095 pastebuffer_help
, pastebuffer_syntax
}
8097 {"Quit", 0, ActionQuit
,
8098 quit_help
, quit_syntax
}
8100 {"RemoveSelected", 0, ActionRemoveSelected
,
8101 removeselected_help
, removeselected_syntax
}
8103 {"Renumber", 0, ActionRenumber
,
8104 renumber_help
, renumber_syntax
}
8106 {"RipUp", 0, ActionRipUp
,
8107 ripup_help
, ripup_syntax
}
8109 {"Select", 0, ActionSelect
,
8110 select_help
, select_syntax
}
8112 {"Unselect", 0, ActionUnselect
,
8113 unselect_help
, unselect_syntax
}
8115 {"SaveSettings", 0, ActionSaveSettings
,
8116 savesettings_help
, savesettings_syntax
}
8118 {"SaveTo", 0, ActionSaveTo
,
8119 saveto_help
, saveto_syntax
}
8121 {"SetSquare", 0, ActionSetSquare
,
8122 setsquare_help
, setsquare_syntax
}
8124 {"SetOctagon", 0, ActionSetOctagon
,
8125 setoctagon_help
, setoctagon_syntax
}
8127 {"SetThermal", 0, ActionSetThermal
,
8128 setthermal_help
, setthermal_syntax
}
8130 {"SetValue", 0, ActionSetValue
,
8131 setvalue_help
, setvalue_syntax
}
8133 {"ToggleHideName", 0, ActionToggleHideName
,
8134 togglehidename_help
, togglehidename_syntax
}
8136 {"Undo", 0, ActionUndo
,
8137 undo_help
, undo_syntax
}
8139 {"Redo", 0, ActionRedo
,
8140 redo_help
, redo_syntax
}
8142 {"SetSame", N_("Select item to use attributes from"), ActionSetSame
,
8143 setsame_help
, setsame_syntax
}
8145 {"SetFlag", 0, ActionSetFlag
,
8146 setflag_help
, setflag_syntax
}
8148 {"ClrFlag", 0, ActionClrFlag
,
8149 clrflag_help
, clrflag_syntax
}
8151 {"ChangeFlag", 0, ActionChangeFlag
,
8152 changeflag_help
, changeflag_syntax
}
8154 {"Polygon", 0, ActionPolygon
,
8155 polygon_help
, polygon_syntax
}
8157 {"RouteStyle", 0, ActionRouteStyle
,
8158 routestyle_help
, routestyle_syntax
}
8160 {"MoveObject", N_("Select an Object"), ActionMoveObject
,
8161 moveobject_help
, moveobject_syntax
}
8163 {"MoveToCurrentLayer", 0, ActionMoveToCurrentLayer
,
8164 movetocurrentlayer_help
, movetocurrentlayer_syntax
}
8166 {"New", 0, ActionNew
,
8167 new_help
, new_syntax
}
8169 {"pscalib", 0, ActionPSCalib
}
8171 {"ElementList", 0, ActionElementList
,
8172 elementlist_help
, elementlist_syntax
}
8174 {"ElementSetAttr", 0, ActionElementSetAttr
,
8175 elementsetattr_help
, elementsetattr_syntax
}
8177 {"ExecCommand", 0, ActionExecCommand
,
8178 execcommand_help
, execcommand_syntax
}
8180 {"Import", 0, ActionImport
,
8181 import_help
, import_syntax
}
8185 REGISTER_ACTIONS (action_action_list
)