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 /* ---------------------------------------------------------------------------
121 F_ElementConnections
,
162 F_ResetLinesAndPolygons
,
163 F_ResetPinsViasAndPads
,
184 F_ToggleAllDirections
,
195 F_ToggleRubberBandMode
,
196 F_ToggleStartDirection
,
201 F_ToggleThindrawPoly
,
215 typedef struct /* used to identify subfunctions */
222 /* --------------------------------------------------------------------------- */
224 /* %start-doc actions 00delta
226 Many actions take a @code{delta} parameter as the last parameter,
227 which is an amount to change something. That @code{delta} may include
228 units, as an additional parameter, such as @code{Action(Object,5,mm)}.
229 If no units are specified, the default is PCB's native units
230 (currently 1/100 mil). Also, if the delta is prefixed by @code{+} or
231 @code{-}, the size is increased or decreased by that amount.
232 Otherwise, the size size is set to the given amount.
236 Action(Object,+0.5,mm)
240 Actions which take a @code{delta} parameter which do not accept all
241 these options will specify what they do take.
245 /* %start-doc actions 00objects
247 Many actions act on indicated objects on the board. They will have
248 parameters like @code{ToggleObject} or @code{SelectedVias} to indicate
249 what group of objects they act on. Unless otherwise specified, these
250 parameters are defined as follows:
256 Affects the object under the mouse pointer. If this action is invoked
257 from a menu or script, the user will be prompted to click on an
258 object, which is then the object affected.
261 @itemx SelectedObjects
263 Affects all objects which are currently selected. At least, all
264 selected objects for which the given action makes sense.
268 @itemx Selected@var{Type}
270 Affects all objects which are both selected and of the @var{Type} specified.
276 /* %start-doc actions 00macros
280 Pins, pads, and vias can have various shapes. All may be round. Pins
281 and pads may be square (obviously "square" pads are usually
282 rectangular). Pins and vias may be octagonal. When you change a
283 shape flag of an element, you actually change all of its pins and
286 Note that the square flag takes precedence over the octagon flag,
287 thus, if both the square and octagon flags are set, the object is
288 square. When the square flag is cleared, the pins and pads will be
289 either round or, if the octagon flag is set, octagonal.
295 /* ---------------------------------------------------------------------------
296 * some local identifiers
298 static PointType InsertedPoint
;
299 static LayerType
*lastLayer
;
312 bool Moving
; /* selected type clicked on */
313 int Hit
; /* move type clicked on */
320 static int defer_updates
= 0;
321 static int defer_needs_update
= 0;
323 static Cardinal polyIndex
= 0;
324 static bool saved_mode
= false;
325 #ifdef HAVE_LIBSTROKE
326 static bool mid_stroke
= false;
327 static BoxType StrokeBox
;
329 static FunctionType Functions
[] = {
330 {"AddSelected", F_AddSelected
},
332 {"AllConnections", F_AllConnections
},
333 {"AllRats", F_AllRats
},
334 {"AllUnusedPins", F_AllUnusedPins
},
338 {"Description", F_Description
},
339 {"Cancel", F_Cancel
},
340 {"Center", F_Center
},
342 {"ClearAndRedraw", F_ClearAndRedraw
},
343 {"ClearList", F_ClearList
},
346 {"Connection", F_Connection
},
347 {"Convert", F_Convert
},
349 {"CycleClip", F_CycleClip
},
350 {"CycleCrosshair", F_CycleCrosshair
},
351 {"DeleteRats", F_DeleteRats
},
353 {"DrillReport", F_DrillReport
},
354 {"Element", F_Element
},
355 {"ElementByName", F_ElementByName
},
356 {"ElementConnections", F_ElementConnections
},
357 {"ElementToBuffer", F_ElementToBuffer
},
358 {"Escape", F_Escape
},
360 {"FlipElement", F_FlipElement
},
361 {"FoundPins", F_FoundPins
},
363 {"InsertPoint", F_InsertPoint
},
365 {"Layout", F_Layout
},
366 {"LayoutAs", F_LayoutAs
},
367 {"LayoutToBuffer", F_LayoutToBuffer
},
369 {"LineSize", F_LineSize
},
371 {"Mirror", F_Mirror
},
373 {"NameOnPCB", F_NameOnPCB
},
374 {"Netlist", F_Netlist
},
375 {"NetByName", F_NetByName
},
377 {"Notify", F_Notify
},
378 {"Object", F_Object
},
379 {"ObjectByName", F_ObjectByName
},
380 {"PasteBuffer", F_PasteBuffer
},
381 {"PadByName", F_PadByName
},
382 {"PinByName", F_PinByName
},
383 {"PinOrPadName", F_PinOrPadName
},
384 {"Pinout", F_Pinout
},
385 {"Polygon", F_Polygon
},
386 {"PolygonHole", F_PolygonHole
},
387 {"PreviousPoint", F_PreviousPoint
},
388 {"RatsNest", F_RatsNest
},
389 {"Rectangle", F_Rectangle
},
390 {"Redraw", F_Redraw
},
391 {"Release", F_Release
},
392 {"Remove", F_Remove
},
393 {"RemoveSelected", F_RemoveSelected
},
394 {"Report", F_Report
},
396 {"ResetLinesAndPolygons", F_ResetLinesAndPolygons
},
397 {"ResetPinsViasAndPads", F_ResetPinsViasAndPads
},
398 {"Restore", F_Restore
},
399 {"Revert", F_Revert
},
400 {"Rotate", F_Rotate
},
402 {"Selected", F_Selected
},
403 {"SelectedArcs", F_SelectedArcs
},
404 {"SelectedElements", F_SelectedElements
},
405 {"SelectedLines", F_SelectedLines
},
406 {"SelectedNames", F_SelectedNames
},
407 {"SelectedObjects", F_SelectedObjects
},
408 {"SelectedPins", F_SelectedPins
},
409 {"SelectedPads", F_SelectedPads
},
410 {"SelectedRats", F_SelectedRats
},
411 {"SelectedTexts", F_SelectedTexts
},
412 {"SelectedVias", F_SelectedVias
},
413 {"Stroke", F_Stroke
},
415 {"TextByName", F_TextByName
},
416 {"TextScale", F_TextScale
},
417 {"Thermal", F_Thermal
},
418 {"ToLayout", F_ToLayout
},
419 {"Toggle45Degree", F_ToggleAllDirections
},
420 {"ToggleClearLine", F_ToggleClearLine
},
421 {"ToggleFullPoly", F_ToggleFullPoly
},
422 {"ToggleGrid", F_ToggleGrid
},
423 {"ToggleMask", F_ToggleMask
},
424 {"ToggleName", F_ToggleName
},
425 {"ToggleObject", F_ToggleObject
},
426 {"ToggleRubberBandMode", F_ToggleRubberBandMode
},
427 {"ToggleStartDirection", F_ToggleStartDirection
},
428 {"ToggleSnapPin", F_ToggleSnapPin
},
429 {"ToggleThindraw", F_ToggleThindraw
},
430 {"ToggleThindrawPoly", F_ToggleThindrawPoly
},
431 {"ToggleLockNames", F_ToggleLockNames
},
432 {"ToggleOnlyNames", F_ToggleOnlyNames
},
433 {"ToggleHideNames", F_ToggleHideNames
},
434 {"ToggleCheckPlanes", F_ToggleCheckPlanes
},
435 {"ToggleLocalRef", F_ToggleLocalRef
},
436 {"ToggleOrthoMove", F_ToggleOrthoMove
},
437 {"ToggleShowDRC", F_ToggleShowDRC
},
438 {"ToggleLiveRoute", F_ToggleLiveRoute
},
439 {"ToggleAutoDRC", F_ToggleAutoDRC
},
440 {"ToggleUniqueNames", F_ToggleUniqueNames
},
443 {"ViaByName", F_ViaByName
},
444 {"ViaSize", F_ViaSize
},
445 {"ViaDrillingHole", F_ViaDrillingHole
},
449 /* ---------------------------------------------------------------------------
450 * some local routines
452 static int GetFunctionID (String
);
453 static void AdjustAttachedBox (void);
454 static void NotifyLine (void);
455 static void NotifyBlock (void);
456 static void NotifyMode (void);
457 static void ClearWarnings (void);
458 #ifdef HAVE_LIBSTROKE
459 static void FinishStroke (void);
460 extern void stroke_init (void);
461 extern void stroke_record (int x
, int y
);
462 extern int stroke_trans (char *s
);
464 static void ChangeFlag (char *, char *, int, char *);
466 #define ARG(n) (argc > (n) ? argv[n] : NULL)
468 #ifdef HAVE_LIBSTROKE
470 /* ---------------------------------------------------------------------------
471 * FinishStroke - try to recognize the stroke sent
479 void *ptr1
, *ptr2
, *ptr3
;
482 if (stroke_trans (msg
))
488 if (Settings
.Mode
== LINE_MODE
)
498 RotateScreenObject (StrokeBox
.X1
, StrokeBox
.Y1
, SWAP_IDENT
? 1 : 3);
504 RotateScreenObject (StrokeBox
.X1
, StrokeBox
.Y1
, SWAP_IDENT
? 3 : 1);
510 SetMode (ARROW_MODE
);
535 /* XXX: FIXME: Call a zoom-extents action */
546 /* XXX: FIXME: Zoom to fit the box StrokeBox.[X1,Y1] - StrokeBox.[X2,Y2] */
550 Message (_("Unknown stroke %s\n"), msg
);
559 /* ---------------------------------------------------------------------------
560 * Clear warning color from pins/pads
565 Settings
.RatWarn
= false;
566 ALLPIN_LOOP (PCB
->Data
);
568 if (TEST_FLAG (WARNFLAG
, pin
))
570 CLEAR_FLAG (WARNFLAG
, pin
);
575 ALLPAD_LOOP (PCB
->Data
);
577 if (TEST_FLAG (WARNFLAG
, pad
))
579 CLEAR_FLAG (WARNFLAG
, pad
);
587 /* ---------------------------------------------------------------------------
589 * This is called a clicktime after a mouse down, to we can distinguish
590 * between short clicks (typically: select or create something) and long
591 * clicks. Long clicks typically drag something.
598 notify_crosshair_change (false);
600 if (Note
.Moving
&& !gui
->shift_is_pressed ())
602 Note
.Buffer
= Settings
.BufferNumber
;
603 SetBufferNumber (MAX_BUFFER
- 1);
604 ClearBuffer (PASTEBUFFER
);
605 AddSelectedToBuffer (PASTEBUFFER
, Note
.X
, Note
.Y
, true);
606 SaveUndoSerialNumber ();
610 SetMode (PASTEBUFFER_MODE
);
612 else if (Note
.Hit
&& !gui
->shift_is_pressed ())
616 SetMode (gui
->control_is_pressed ()? COPY_MODE
: MOVE_MODE
);
617 Crosshair
.AttachedObject
.Ptr1
= Note
.ptr1
;
618 Crosshair
.AttachedObject
.Ptr2
= Note
.ptr2
;
619 Crosshair
.AttachedObject
.Ptr3
= Note
.ptr3
;
620 Crosshair
.AttachedObject
.Type
= Note
.Hit
;
621 AttachForCopy (Note
.X
, Note
.Y
);
629 SaveUndoSerialNumber ();
634 /* unselect first if shift key not down */
635 if (!gui
->shift_is_pressed () && SelectBlock (&box
, false))
636 SetChangedFlag (true);
638 Crosshair
.AttachedBox
.Point1
.X
= Note
.X
;
639 Crosshair
.AttachedBox
.Point1
.Y
= Note
.Y
;
641 notify_crosshair_change (true);
645 /* ---------------------------------------------------------------------------
647 * This is typically called when the mouse has moved or the mouse
648 * button was released.
664 Note
.Click
= false; /* inhibit timer action */
665 SaveUndoSerialNumber ();
666 /* unselect first if shift key not down */
667 if (!gui
->shift_is_pressed ())
669 if (SelectBlock (&box
, false))
670 SetChangedFlag (true);
678 RestoreUndoSerialNumber ();
680 SetChangedFlag (true);
684 else if (Note
.Moving
)
686 RestoreUndoSerialNumber ();
688 ClearBuffer (PASTEBUFFER
);
689 SetBufferNumber (Note
.Buffer
);
698 else if (Settings
.Mode
== ARROW_MODE
)
700 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
701 Crosshair
.AttachedBox
.Point2
.X
);
702 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
703 Crosshair
.AttachedBox
.Point2
.Y
);
704 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
705 Crosshair
.AttachedBox
.Point2
.X
);
706 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
707 Crosshair
.AttachedBox
.Point2
.Y
);
708 RestoreUndoSerialNumber ();
709 if (SelectBlock (&box
, true))
710 SetChangedFlag (true);
712 IncrementUndoSerialNumber ();
713 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
720 /* ---------------------------------------------------------------------------
721 * get function ID of passed string
724 static char function_hash
[HSIZE
];
725 static int hash_initted
= 0;
734 i
= (i
* 13) ^ (unsigned char)tolower((int) *s
);
737 i
= (unsigned int)i
% HSIZE
;
742 GetFunctionID (String Ident
)
752 if (HSIZE
< ENTRIES (Functions
) * 2)
754 fprintf(stderr
, _("Error: function hash size too small (%d vs %lu at %s:%d)\n"),
755 HSIZE
, (unsigned long) ENTRIES (Functions
)*2, __FILE__
, __LINE__
);
758 if (ENTRIES (Functions
) > 254)
760 /* Change 'char' to 'int' and remove this when we get to 256
762 fprintf(stderr
, _("Error: function hash type too small (%d vs %lu at %s:%d)\n"),
763 256, (unsigned long) ENTRIES (Functions
), __FILE__
, __LINE__
);
767 for (i
=ENTRIES (Functions
)-1; i
>=0; i
--)
769 h
= hashfunc (Functions
[i
].Identifier
);
770 while (function_hash
[h
])
772 function_hash
[h
] = i
+ 1;
776 i
= hashfunc (Ident
);
779 /* We enforce the "hash table bigger than function table" rule,
780 so we know there will be at least one zero entry to find. */
781 if (!function_hash
[i
])
783 if (!strcasecmp (Ident
, Functions
[function_hash
[i
]-1].Identifier
))
784 return ((int) Functions
[function_hash
[i
]-1].ID
);
789 /* ---------------------------------------------------------------------------
790 * set new coordinates if in 'RECTANGLE' mode
791 * the cursor shape is also adjusted
794 AdjustAttachedBox (void)
796 if (Settings
.Mode
== ARC_MODE
)
798 Crosshair
.AttachedBox
.otherway
= gui
->shift_is_pressed ();
801 switch (Crosshair
.AttachedBox
.State
)
803 case STATE_SECOND
: /* one corner is selected */
805 /* update coordinates */
806 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
807 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
813 /* ---------------------------------------------------------------------------
814 * adjusts the objects which are to be created like attached lines...
817 AdjustAttachedObjects (void)
820 switch (Settings
.Mode
)
822 /* update at least an attached block (selection) */
825 if (Crosshair
.AttachedBox
.State
)
827 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
828 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
832 /* rectangle creation mode */
835 AdjustAttachedBox ();
838 /* polygon creation mode */
840 case POLYGONHOLE_MODE
:
841 AdjustAttachedLine ();
843 /* line creation mode */
845 if (PCB
->RatDraw
|| PCB
->Clipping
== 0)
846 AdjustAttachedLine ();
848 AdjustTwoLine (PCB
->Clipping
- 1);
850 /* point insertion mode */
851 case INSERTPOINT_MODE
:
852 pnt
= AdjustInsertPoint ();
854 InsertedPoint
= *pnt
;
861 /* ---------------------------------------------------------------------------
862 * creates points of a line
868 void *ptr1
, *ptr2
, *ptr3
;
870 if (!Marked
.status
|| TEST_FLAG (LOCALREFFLAG
, PCB
))
871 SetLocalRef (Crosshair
.X
, Crosshair
.Y
, true);
872 switch (Crosshair
.AttachedLine
.State
)
874 case STATE_FIRST
: /* first point */
875 if (PCB
->RatDraw
&& SearchScreen (Crosshair
.X
, Crosshair
.Y
,
876 PAD_TYPE
| PIN_TYPE
, &ptr1
, &ptr1
,
882 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
884 type
= SearchScreen (Crosshair
.X
, Crosshair
.Y
,
885 PIN_TYPE
| PAD_TYPE
| VIA_TYPE
, &ptr1
, &ptr2
,
887 LookupConnection (Crosshair
.X
, Crosshair
.Y
, true, 1, CONNECTEDFLAG
, false);
888 LookupConnection (Crosshair
.X
, Crosshair
.Y
, true, 1, FOUNDFLAG
, true);
890 if (type
== PIN_TYPE
|| type
== VIA_TYPE
)
892 Crosshair
.AttachedLine
.Point1
.X
=
893 Crosshair
.AttachedLine
.Point2
.X
= ((PinType
*) ptr2
)->X
;
894 Crosshair
.AttachedLine
.Point1
.Y
=
895 Crosshair
.AttachedLine
.Point2
.Y
= ((PinType
*) ptr2
)->Y
;
897 else if (type
== PAD_TYPE
)
899 PadType
*pad
= (PadType
*) ptr2
;
900 double d1
= Distance (Crosshair
.X
, Crosshair
.Y
, pad
->Point1
.X
, pad
->Point1
.Y
);
901 double d2
= Distance (Crosshair
.X
, Crosshair
.Y
, pad
->Point2
.X
, pad
->Point2
.Y
);
904 Crosshair
.AttachedLine
.Point1
=
905 Crosshair
.AttachedLine
.Point2
= pad
->Point2
;
909 Crosshair
.AttachedLine
.Point1
=
910 Crosshair
.AttachedLine
.Point2
= pad
->Point1
;
915 Crosshair
.AttachedLine
.Point1
.X
=
916 Crosshair
.AttachedLine
.Point2
.X
= Crosshair
.X
;
917 Crosshair
.AttachedLine
.Point1
.Y
=
918 Crosshair
.AttachedLine
.Point2
.Y
= Crosshair
.Y
;
920 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
924 /* fall through to third state too */
926 default: /* all following points */
927 Crosshair
.AttachedLine
.State
= STATE_THIRD
;
932 /* ---------------------------------------------------------------------------
933 * create first or second corner of a marked block
938 notify_crosshair_change (false);
939 switch (Crosshair
.AttachedBox
.State
)
941 case STATE_FIRST
: /* setup first point */
942 Crosshair
.AttachedBox
.Point1
.X
=
943 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
944 Crosshair
.AttachedBox
.Point1
.Y
=
945 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
946 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
949 case STATE_SECOND
: /* setup second point */
950 Crosshair
.AttachedBox
.State
= STATE_THIRD
;
953 notify_crosshair_change (true);
957 /* ---------------------------------------------------------------------------
959 * This is called after every mode change, like mouse button pressed,
960 * mouse button released, dragging something started or a different tool
961 * selected. It does what's appropriate for the current mode setting.
962 * This can also mean creation of an object at the current crosshair location.
964 * new created objects are added to the create undo list of course
969 void *ptr1
, *ptr2
, *ptr3
;
972 if (Settings
.RatWarn
)
974 switch (Settings
.Mode
)
982 /* do something after click time */
983 gui
->add_timer (click_cb
, CLICK_TIME
, hv
);
985 /* see if we clicked on something already selected
986 * (Note.Moving) or clicked on a MOVE_TYPE
989 for (test
= (SELECT_TYPES
| MOVE_TYPES
) & ~RATLINE_TYPE
;
992 type
= SearchScreen (Note
.X
, Note
.Y
, test
, &ptr1
, &ptr2
, &ptr3
);
993 if (!Note
.Hit
&& (type
& MOVE_TYPES
) &&
994 !TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
1001 if (!Note
.Moving
&& (type
& SELECT_TYPES
) &&
1002 TEST_FLAG (SELECTEDFLAG
, (PinType
*) ptr2
))
1004 if ((Note
.Hit
&& Note
.Moving
) || type
== NO_TYPE
)
1016 Message (_("You must turn via visibility on before\n"
1017 "you can place vias\n"));
1020 if ((via
= CreateNewVia (PCB
->Data
, Note
.X
, Note
.Y
,
1021 Settings
.ViaThickness
, 2 * Settings
.Keepaway
,
1022 0, Settings
.ViaDrillingHole
, NULL
,
1023 NoFlags ())) != NULL
)
1025 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1026 if (gui
->shift_is_pressed ())
1027 ChangeObjectThermal (VIA_TYPE
, via
, via
, via
, PCB
->ThermStyle
);
1028 IncrementUndoSerialNumber ();
1037 switch (Crosshair
.AttachedBox
.State
)
1040 Crosshair
.AttachedBox
.Point1
.X
=
1041 Crosshair
.AttachedBox
.Point2
.X
= Note
.X
;
1042 Crosshair
.AttachedBox
.Point1
.Y
=
1043 Crosshair
.AttachedBox
.Point2
.Y
= Note
.Y
;
1044 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
1054 wx
= Note
.X
- Crosshair
.AttachedBox
.Point1
.X
;
1055 wy
= Note
.Y
- Crosshair
.AttachedBox
.Point1
.Y
;
1056 if (XOR (Crosshair
.AttachedBox
.otherway
, abs (wy
) > abs (wx
)))
1058 Crosshair
.AttachedBox
.Point2
.X
=
1059 Crosshair
.AttachedBox
.Point1
.X
+ abs (wy
) * SGNZ (wx
);
1060 sa
= (wx
>= 0) ? 0 : 180;
1062 if (abs (wy
) / 2 >= abs (wx
))
1063 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 45 : -45;
1066 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 90 : -90;
1070 Crosshair
.AttachedBox
.Point2
.Y
=
1071 Crosshair
.AttachedBox
.Point1
.Y
+ abs (wx
) * SGNZ (wy
);
1072 sa
= (wy
>= 0) ? -90 : 90;
1074 if (abs (wx
) / 2 >= abs (wy
))
1075 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -45 : 45;
1078 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -90 : 90;
1081 if (abs (wy
) > 0 && (arc
= CreateNewArcOnLayer (CURRENT
,
1105 bx
= GetArcEnds (arc
);
1106 Crosshair
.AttachedBox
.Point1
.X
=
1107 Crosshair
.AttachedBox
.Point2
.X
= bx
->X2
;
1108 Crosshair
.AttachedBox
.Point1
.Y
=
1109 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y2
;
1110 AddObjectToCreateUndoList (ARC_TYPE
, CURRENT
, arc
, arc
);
1111 IncrementUndoSerialNumber ();
1113 DrawArc (CURRENT
, arc
);
1115 Crosshair
.AttachedBox
.State
= STATE_THIRD
;
1124 type
= SearchScreen (Note
.X
, Note
.Y
, LOCK_TYPES
, &ptr1
, &ptr2
, &ptr3
);
1125 if (type
== ELEMENT_TYPE
)
1127 ElementType
*element
= (ElementType
*) ptr2
;
1129 TOGGLE_FLAG (LOCKFLAG
, element
);
1132 TOGGLE_FLAG (LOCKFLAG
, pin
);
1133 CLEAR_FLAG (SELECTEDFLAG
, pin
);
1138 TOGGLE_FLAG (LOCKFLAG
, pad
);
1139 CLEAR_FLAG (SELECTEDFLAG
, pad
);
1142 CLEAR_FLAG (SELECTEDFLAG
, element
);
1143 /* always re-draw it since I'm too lazy
1144 * to tell if a selected flag changed
1146 DrawElement (element
);
1148 SetChangedFlag (true);
1149 hid_actionl ("Report", "Object", NULL
);
1151 else if (type
!= NO_TYPE
)
1153 TextType
*thing
= (TextType
*) ptr3
;
1154 TOGGLE_FLAG (LOCKFLAG
, thing
);
1155 if (TEST_FLAG (LOCKFLAG
, thing
)
1156 && TEST_FLAG (SELECTEDFLAG
, thing
))
1158 /* this is not un-doable since LOCK isn't */
1159 CLEAR_FLAG (SELECTEDFLAG
, thing
);
1160 DrawObject (type
, ptr1
, ptr2
);
1163 SetChangedFlag (true);
1164 hid_actionl ("Report", "Object", NULL
);
1172 SearchScreen (Note
.X
, Note
.Y
, PIN_TYPES
, &ptr1
, &ptr2
,
1174 && !TEST_FLAG (HOLEFLAG
, (PinType
*) ptr3
))
1176 if (gui
->shift_is_pressed ())
1178 int tstyle
= GET_THERM (INDEXOFCURRENT
, (PinType
*) ptr3
);
1182 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, tstyle
);
1184 else if (GET_THERM (INDEXOFCURRENT
, (PinType
*) ptr3
))
1185 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, 0);
1187 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, PCB
->ThermStyle
);
1193 /* do update of position */
1195 if (Crosshair
.AttachedLine
.State
!= STATE_THIRD
)
1198 /* Remove anchor if clicking on start point;
1199 * this means we can't paint 0 length lines
1200 * which could be used for square SMD pads.
1201 * Instead use a very small delta, or change
1202 * the file after saving.
1204 if (Crosshair
.X
== Crosshair
.AttachedLine
.Point1
.X
1205 && Crosshair
.Y
== Crosshair
.AttachedLine
.Point1
.Y
)
1207 SetMode (LINE_MODE
);
1214 if ((line
= AddNet ()))
1217 AddObjectToCreateUndoList (RATLINE_TYPE
, line
, line
, line
);
1218 IncrementUndoSerialNumber ();
1220 Crosshair
.AttachedLine
.Point1
.X
=
1221 Crosshair
.AttachedLine
.Point2
.X
;
1222 Crosshair
.AttachedLine
.Point1
.Y
=
1223 Crosshair
.AttachedLine
.Point2
.Y
;
1229 /* create line if both ends are determined && length != 0 */
1234 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && !TEST_SILK_LAYER (CURRENT
))
1235 line_flags
|= CONNECTEDFLAG
| FOUNDFLAG
;
1237 if (TEST_FLAG (CLEARNEWFLAG
, PCB
))
1238 line_flags
|= CLEARLINEFLAG
;
1241 && Crosshair
.AttachedLine
.Point1
.X
==
1242 Crosshair
.AttachedLine
.Point2
.X
1243 && Crosshair
.AttachedLine
.Point1
.Y
==
1244 Crosshair
.AttachedLine
.Point2
.Y
1245 && (Crosshair
.AttachedLine
.Point2
.X
!= Note
.X
1246 || Crosshair
.AttachedLine
.Point2
.Y
!= Note
.Y
))
1248 /* We will only need to paint the second line segment.
1249 Since we only check for vias on the first segment,
1250 swap them so the non-empty segment is the first segment. */
1251 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1252 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1255 if ((Crosshair
.AttachedLine
.Point1
.X
!=
1256 Crosshair
.AttachedLine
.Point2
.X
1257 || Crosshair
.AttachedLine
.Point1
.Y
!=
1258 Crosshair
.AttachedLine
.Point2
.Y
)
1260 CreateDrawnLineOnLayer (CURRENT
,
1261 Crosshair
.AttachedLine
.Point1
.X
,
1262 Crosshair
.AttachedLine
.Point1
.Y
,
1263 Crosshair
.AttachedLine
.Point2
.X
,
1264 Crosshair
.AttachedLine
.Point2
.Y
,
1265 Settings
.LineThickness
,
1266 2 * Settings
.Keepaway
,
1267 MakeFlags (line_flags
))) != NULL
)
1272 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1273 DrawLine (CURRENT
, line
);
1274 /* place a via if vias are visible, the layer is
1275 in a new group since the last line and there
1276 isn't a pin already here */
1277 if (PCB
->ViaOn
&& GetLayerGroupNumberByPointer (CURRENT
) !=
1278 GetLayerGroupNumberByPointer (lastLayer
) &&
1279 SearchObjectByLocation (PIN_TYPES
, &ptr1
, &ptr2
, &ptr3
,
1280 Crosshair
.AttachedLine
.Point1
.X
,
1281 Crosshair
.AttachedLine
.Point1
.Y
,
1282 Settings
.ViaThickness
/ 2) ==
1285 CreateNewVia (PCB
->Data
,
1286 Crosshair
.AttachedLine
.Point1
.X
,
1287 Crosshair
.AttachedLine
.Point1
.Y
,
1288 Settings
.ViaThickness
,
1289 2 * Settings
.Keepaway
, 0,
1290 Settings
.ViaDrillingHole
, NULL
,
1291 NoFlags ())) != NULL
)
1293 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1296 /* copy the coordinates */
1297 Crosshair
.AttachedLine
.Point1
.X
=
1298 Crosshair
.AttachedLine
.Point2
.X
;
1299 Crosshair
.AttachedLine
.Point1
.Y
=
1300 Crosshair
.AttachedLine
.Point2
.Y
;
1301 IncrementUndoSerialNumber ();
1302 lastLayer
= CURRENT
;
1304 if (PCB
->Clipping
&& (Note
.X
!= Crosshair
.AttachedLine
.Point2
.X
1306 Crosshair
.AttachedLine
.Point2
.Y
)
1308 CreateDrawnLineOnLayer (CURRENT
,
1309 Crosshair
.AttachedLine
.Point2
.X
,
1310 Crosshair
.AttachedLine
.Point2
.Y
,
1312 Settings
.LineThickness
,
1313 2 * Settings
.Keepaway
,
1314 MakeFlags (line_flags
))) != NULL
)
1317 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1318 IncrementUndoSerialNumber ();
1319 DrawLine (CURRENT
, line
);
1320 /* move to new start point */
1321 Crosshair
.AttachedLine
.Point1
.X
= Note
.X
;
1322 Crosshair
.AttachedLine
.Point1
.Y
= Note
.Y
;
1323 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1324 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1325 if (TEST_FLAG (SWAPSTARTDIRFLAG
, PCB
))
1330 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && !TEST_SILK_LAYER (CURRENT
))
1331 LookupConnection (Note
.X
, Note
.Y
, true, 1, CONNECTEDFLAG
, false);
1336 case RECTANGLE_MODE
:
1337 /* do update of position */
1340 /* create rectangle if both corners are determined
1341 * and width, height are != 0
1343 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
1344 Crosshair
.AttachedBox
.Point1
.X
!= Crosshair
.AttachedBox
.Point2
.X
&&
1345 Crosshair
.AttachedBox
.Point1
.Y
!= Crosshair
.AttachedBox
.Point2
.Y
)
1347 PolygonType
*polygon
;
1349 int flags
= CLEARPOLYFLAG
;
1350 if (TEST_FLAG (NEWFULLPOLYFLAG
, PCB
))
1351 flags
|= FULLPOLYFLAG
;
1352 if ((polygon
= CreateNewPolygonFromRectangle (CURRENT
,
1354 AttachedBox
.Point1
.X
,
1356 AttachedBox
.Point1
.Y
,
1358 AttachedBox
.Point2
.X
,
1360 AttachedBox
.Point2
.Y
,
1365 AddObjectToCreateUndoList (POLYGON_TYPE
, CURRENT
,
1367 IncrementUndoSerialNumber ();
1368 DrawPolygon (CURRENT
, polygon
);
1372 /* reset state to 'first corner' */
1373 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
1381 if ((string
= gui
->prompt_for (_("Enter text:"), "")) != NULL
)
1383 if (strlen(string
) > 0)
1386 int flag
= CLEARLINEFLAG
;
1388 if (GetLayerGroupNumberByNumber (INDEXOFCURRENT
) ==
1389 GetLayerGroupNumberByNumber (solder_silk_layer
))
1390 flag
|= ONSOLDERFLAG
;
1391 if ((text
= CreateNewText (CURRENT
, &PCB
->Font
, Note
.X
,
1392 Note
.Y
, 0, Settings
.TextScale
,
1393 string
, MakeFlags (flag
))) != NULL
)
1395 AddObjectToCreateUndoList (TEXT_TYPE
, CURRENT
, text
, text
);
1396 IncrementUndoSerialNumber ();
1397 DrawText (CURRENT
, text
);
1408 PointType
*points
= Crosshair
.AttachedPolygon
.Points
;
1409 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1411 /* do update of position; use the 'LINE_MODE' mechanism */
1414 /* check if this is the last point of a polygon */
1416 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1417 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1419 CopyAttachedPolygonToLayer ();
1424 /* create new point if it's the first one or if it's
1425 * different to the last one
1428 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1429 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1431 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1432 Crosshair
.AttachedLine
.Point2
.X
,
1433 Crosshair
.AttachedLine
.Point2
.Y
);
1435 /* copy the coordinates */
1436 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1437 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1442 case POLYGONHOLE_MODE
:
1444 switch (Crosshair
.AttachedObject
.State
)
1446 /* first notify, lookup object */
1448 Crosshair
.AttachedObject
.Type
=
1449 SearchScreen (Note
.X
, Note
.Y
, POLYGON_TYPE
,
1450 &Crosshair
.AttachedObject
.Ptr1
,
1451 &Crosshair
.AttachedObject
.Ptr2
,
1452 &Crosshair
.AttachedObject
.Ptr3
);
1454 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1456 if (TEST_FLAG (LOCKFLAG
, (PolygonType
*)
1457 Crosshair
.AttachedObject
.Ptr2
))
1459 Message (_("Sorry, the object is locked\n"));
1460 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1464 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1468 /* second notify, insert new point into object */
1471 PointType
*points
= Crosshair
.AttachedPolygon
.Points
;
1472 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1473 POLYAREA
*original
, *new_hole
, *result
;
1476 /* do update of position; use the 'LINE_MODE' mechanism */
1479 /* check if this is the last point of a polygon */
1481 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1482 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1484 /* Create POLYAREAs from the original polygon
1485 * and the new hole polygon */
1486 original
= PolygonToPoly ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
);
1487 new_hole
= PolygonToPoly (&Crosshair
.AttachedPolygon
);
1489 /* Subtract the hole from the original polygon shape */
1490 poly_Boolean_free (original
, new_hole
, &result
, PBO_SUB
);
1492 /* Convert the resulting polygon(s) into a new set of nodes
1493 * and place them on the page. Delete the original polygon.
1495 SaveUndoSerialNumber ();
1496 Flags
= ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
)->Flags
;
1497 PolyToPolygonsOnLayer (PCB
->Data
, (LayerType
*)Crosshair
.AttachedObject
.Ptr1
,
1499 RemoveObject (POLYGON_TYPE
,
1500 Crosshair
.AttachedObject
.Ptr1
,
1501 Crosshair
.AttachedObject
.Ptr2
,
1502 Crosshair
.AttachedObject
.Ptr3
);
1503 RestoreUndoSerialNumber ();
1504 IncrementUndoSerialNumber ();
1507 /* reset state of attached line */
1508 memset (&Crosshair
.AttachedPolygon
, 0, sizeof (PolygonType
));
1509 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
1515 /* create new point if it's the first one or if it's
1516 * different to the last one
1519 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1520 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1522 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1523 Crosshair
.AttachedLine
.Point2
.X
,
1524 Crosshair
.AttachedLine
.Point2
.Y
);
1526 /* copy the coordinates */
1527 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1528 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1537 case PASTEBUFFER_MODE
:
1539 TextType estr
[MAX_ELEMENTNAMES
];
1542 if (gui
->shift_is_pressed ())
1545 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1547 if (type
== ELEMENT_TYPE
)
1549 e
= (ElementType
*) ptr1
;
1554 memcpy (estr
, e
->Name
,
1555 MAX_ELEMENTNAMES
* sizeof (TextType
));
1556 for (i
= 0; i
< MAX_ELEMENTNAMES
; ++i
)
1557 estr
[i
].TextString
= estr
[i
].TextString
? strdup(estr
[i
].TextString
) : NULL
;
1562 if (CopyPastebufferToLayout (Note
.X
, Note
.Y
))
1563 SetChangedFlag (true);
1567 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1569 if (type
== ELEMENT_TYPE
&& ptr1
)
1572 e
= (ElementType
*) ptr1
;
1574 save_n
= NAME_INDEX (PCB
);
1576 for (i
= 0; i
< MAX_ELEMENTNAMES
; i
++)
1579 EraseElementName (e
);
1580 r_delete_entry (PCB
->Data
->name_tree
[i
],
1581 (BoxType
*) & (e
->Name
[i
]));
1582 memcpy (&(e
->Name
[i
]), &(estr
[i
]), sizeof (TextType
));
1583 e
->Name
[i
].Element
= e
;
1584 SetTextBoundingBox (&PCB
->Font
, &(e
->Name
[i
]));
1585 r_insert_entry (PCB
->Data
->name_tree
[i
],
1586 (BoxType
*) & (e
->Name
[i
]), 0);
1588 DrawElementName (e
);
1597 SearchScreen (Note
.X
, Note
.Y
, REMOVE_TYPES
, &ptr1
, &ptr2
,
1600 if (TEST_FLAG (LOCKFLAG
, (LineType
*) ptr2
))
1602 Message (_("Sorry, the object is locked\n"));
1605 if (type
== ELEMENT_TYPE
)
1607 RubberbandType
*ptr
;
1610 Crosshair
.AttachedObject
.RubberbandN
= 0;
1611 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
1612 ptr
= Crosshair
.AttachedObject
.Rubberband
;
1613 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
; i
++)
1616 EraseRat ((RatType
*) ptr
->Line
);
1617 if (TEST_FLAG (RUBBERENDFLAG
, ptr
->Line
))
1618 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
1619 ptr
->Line
, ptr
->Line
,
1622 TOGGLE_FLAG (RUBBERENDFLAG
, ptr
->Line
); /* only remove line once */
1626 RemoveObject (type
, ptr1
, ptr2
, ptr3
);
1627 IncrementUndoSerialNumber ();
1628 SetChangedFlag (true);
1633 RotateScreenObject (Note
.X
, Note
.Y
,
1634 gui
->shift_is_pressed ()? (SWAP_IDENT
?
1636 : (SWAP_IDENT
? 3 : 1));
1639 /* both are almost the same */
1642 switch (Crosshair
.AttachedObject
.State
)
1644 /* first notify, lookup object */
1647 int types
= (Settings
.Mode
== COPY_MODE
) ?
1648 COPY_TYPES
: MOVE_TYPES
;
1650 Crosshair
.AttachedObject
.Type
=
1651 SearchScreen (Note
.X
, Note
.Y
, types
,
1652 &Crosshair
.AttachedObject
.Ptr1
,
1653 &Crosshair
.AttachedObject
.Ptr2
,
1654 &Crosshair
.AttachedObject
.Ptr3
);
1655 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1657 if (Settings
.Mode
== MOVE_MODE
&&
1658 TEST_FLAG (LOCKFLAG
, (PinType
*)
1659 Crosshair
.AttachedObject
.Ptr2
))
1661 Message (_("Sorry, the object is locked\n"));
1662 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1665 AttachForCopy (Note
.X
, Note
.Y
);
1670 /* second notify, move or copy object */
1672 if (Settings
.Mode
== COPY_MODE
)
1673 CopyObject (Crosshair
.AttachedObject
.Type
,
1674 Crosshair
.AttachedObject
.Ptr1
,
1675 Crosshair
.AttachedObject
.Ptr2
,
1676 Crosshair
.AttachedObject
.Ptr3
,
1677 Note
.X
- Crosshair
.AttachedObject
.X
,
1678 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1681 MoveObjectAndRubberband (Crosshair
.AttachedObject
.Type
,
1682 Crosshair
.AttachedObject
.Ptr1
,
1683 Crosshair
.AttachedObject
.Ptr2
,
1684 Crosshair
.AttachedObject
.Ptr3
,
1685 Note
.X
- Crosshair
.AttachedObject
.X
,
1686 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1687 SetLocalRef (0, 0, false);
1689 SetChangedFlag (true);
1691 /* reset identifiers */
1692 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1693 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1698 /* insert a point into a polygon/line/... */
1699 case INSERTPOINT_MODE
:
1700 switch (Crosshair
.AttachedObject
.State
)
1702 /* first notify, lookup object */
1704 Crosshair
.AttachedObject
.Type
=
1705 SearchScreen (Note
.X
, Note
.Y
, INSERT_TYPES
,
1706 &Crosshair
.AttachedObject
.Ptr1
,
1707 &Crosshair
.AttachedObject
.Ptr2
,
1708 &Crosshair
.AttachedObject
.Ptr3
);
1710 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1712 if (TEST_FLAG (LOCKFLAG
, (PolygonType
*)
1713 Crosshair
.AttachedObject
.Ptr2
))
1715 Message (_("Sorry, the object is locked\n"));
1716 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1721 /* get starting point of nearest segment */
1722 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1725 (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
;
1727 GetLowestDistancePolygonPoint (fake
.poly
, Note
.X
,
1729 fake
.line
.Point1
= fake
.poly
->Points
[polyIndex
];
1730 fake
.line
.Point2
= fake
.poly
->Points
[
1731 prev_contour_point (fake
.poly
, polyIndex
)];
1732 Crosshair
.AttachedObject
.Ptr2
= &fake
.line
;
1735 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1736 InsertedPoint
= *AdjustInsertPoint ();
1741 /* second notify, insert new point into object */
1743 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1744 InsertPointIntoObject (POLYGON_TYPE
,
1745 Crosshair
.AttachedObject
.Ptr1
, fake
.poly
,
1747 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1749 InsertPointIntoObject (Crosshair
.AttachedObject
.Type
,
1750 Crosshair
.AttachedObject
.Ptr1
,
1751 Crosshair
.AttachedObject
.Ptr2
,
1753 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1754 SetChangedFlag (true);
1756 /* reset identifiers */
1757 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1758 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1766 /* --------------------------------------------------------------------------- */
1768 static const char atomic_syntax
[] = "Atomic(Save|Restore|Close|Block)";
1770 static const char atomic_help
[] = "Save or restore the undo serial number.";
1772 /* %start-doc actions Atomic
1774 This action allows making multiple-action bindings into an atomic
1775 operation that will be undone by a single Undo command. For example,
1776 to optimize rat lines, you'd delete the rats and re-add them. To
1777 group these into a single undo, you'd want the deletions and the
1778 additions to have the same undo serial number. So, you @code{Save},
1779 delete the rats, @code{Restore}, add the rats - using the same serial
1780 number as the deletes, then @code{Block}, which checks to see if the
1781 deletions or additions actually did anything. If not, the serial
1782 number is set to the saved number, as there's nothing to undo. If
1783 something did happen, the serial number is incremented so that these
1784 actions are counted as a single undo step.
1789 Saves the undo serial number.
1792 Returns it to the last saved number.
1795 Sets it to 1 greater than the last save.
1798 Does a Restore if there was nothing to undo, else does a Close.
1805 ActionAtomic (int argc
, char **argv
, Coord x
, Coord y
)
1810 switch (GetFunctionID (argv
[0]))
1813 SaveUndoSerialNumber ();
1816 RestoreUndoSerialNumber ();
1819 RestoreUndoSerialNumber ();
1820 IncrementUndoSerialNumber ();
1823 RestoreUndoSerialNumber ();
1825 IncrementUndoSerialNumber ();
1831 /* -------------------------------------------------------------------------- */
1833 static const char drc_syntax
[] = "DRC()";
1835 static const char drc_help
[] = "Invoke the DRC check.";
1837 /* %start-doc actions DRC
1839 Note that the design rule check uses the current board rule settings,
1840 not the current style settings.
1845 ActionDRCheck (int argc
, char **argv
, Coord x
, Coord y
)
1849 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1851 Message (_("%m+Rules are minspace %$mS, minoverlap %$mS "
1852 "minwidth %$mS, minsilk %$mS\n"
1853 "min drill %$mS, min annular ring %$mS\n"),
1854 Settings
.grid_unit
->allow
,
1855 PCB
->Bloat
, PCB
->Shrink
,
1856 PCB
->minWid
, PCB
->minSlk
,
1857 PCB
->minDrill
, PCB
->minRing
);
1860 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1863 Message (_("No DRC problems found.\n"));
1865 Message (_("Found %d design rule errors.\n"), count
);
1867 Message (_("Aborted DRC after %d design rule errors.\n"), -count
);
1872 /* -------------------------------------------------------------------------- */
1874 static const char dumplibrary_syntax
[] = "DumpLibrary()";
1876 static const char dumplibrary_help
[] =
1877 "Display the entire contents of the libraries.";
1879 /* %start-doc actions DumpLibrary
1885 ActionDumpLibrary (int argc
, char **argv
, Coord x
, Coord y
)
1889 printf ("**** Do not count on this format. It will change ****\n\n");
1890 printf ("MenuN = %d\n", Library
.MenuN
);
1891 printf ("MenuMax = %d\n", Library
.MenuMax
);
1892 for (i
= 0; i
< Library
.MenuN
; i
++)
1894 printf ("Library #%d:\n", i
);
1895 printf (" EntryN = %d\n", Library
.Menu
[i
].EntryN
);
1896 printf (" EntryMax = %d\n", Library
.Menu
[i
].EntryMax
);
1897 printf (" Name = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Name
));
1898 printf (" directory = \"%s\"\n",
1899 UNKNOWN (Library
.Menu
[i
].directory
));
1900 printf (" Style = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Style
));
1901 printf (" flag = %d\n", Library
.Menu
[i
].flag
);
1903 for (j
= 0; j
< Library
.Menu
[i
].EntryN
; j
++)
1905 printf (" #%4d: ", j
);
1906 if (Library
.Menu
[i
].Entry
[j
].Template
== (char *) -1)
1908 printf ("newlib: \"%s\"\n",
1909 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
));
1913 printf ("\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"\n",
1914 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
),
1915 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Template
),
1916 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Package
),
1917 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Value
),
1918 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Description
));
1926 /* -------------------------------------------------------------------------- */
1928 static const char flip_syntax
[] = "Flip(Object|Selected|SelectedElements)";
1930 static const char flip_help
[] =
1931 "Flip an element to the opposite side of the board.";
1933 /* %start-doc actions Flip
1935 Note that the location of the element will be symmetric about the
1936 cursor location; i.e. if the part you are pointing at will still be at
1937 the same spot once the element is on the other side. When flipping
1938 multiple elements, this retains their positions relative to each
1939 other, not their absolute positions on the board.
1944 ActionFlip (int argc
, char **argv
, Coord x
, Coord y
)
1946 char *function
= ARG (0);
1947 ElementType
*element
;
1953 switch (GetFunctionID (function
))
1956 if ((SearchScreen (x
, y
, ELEMENT_TYPE
,
1957 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
1959 element
= (ElementType
*) ptrtmp
;
1960 ChangeElementSide (element
, 2 * Crosshair
.Y
- PCB
->MaxHeight
);
1961 IncrementUndoSerialNumber ();
1966 case F_SelectedElements
:
1967 ChangeSelectedElementSide ();
1980 /* -------------------------------------------------------------------------- */
1982 static const char message_syntax
[] = "Message(message)";
1984 static const char message_help
[] = "Writes a message to the log window.";
1986 /* %start-doc actions Message
1988 This action displays a message to the log window. This action is primarily
1989 provided for use by other programs which may interface with PCB. If
1990 multiple arguments are given, each one is sent to the log window
1991 followed by a newline.
1996 ActionMessage (int argc
, char **argv
, Coord x
, Coord y
)
2003 for (i
= 0; i
< argc
; i
++)
2013 /* -------------------------------------------------------------------------- */
2015 static const char setthermal_syntax
[] =
2016 "SetThermal(Object|SelectedPins|SelectedVias|Selected, Style)";
2018 static const char setthermal_help
[] =
2019 "Set the thermal (on the current layer) of pins or vias to the given style.\n"
2020 "Style = 0 means no thermal.\n"
2021 "Style = 1 has diagonal fingers with sharp edges.\n"
2022 "Style = 2 has horizontal and vertical fingers with sharp edges.\n"
2023 "Style = 3 is a solid connection to the plane."
2024 "Style = 4 has diagonal fingers with rounded edges.\n"
2025 "Style = 5 has horizontal and vertical fingers with rounded edges.\n";
2027 /* %start-doc actions SetThermal
2029 This changes how/whether pins or vias connect to any rectangle or polygon
2030 on the current layer. The first argument can specify one object, or all
2031 selected pins, or all selected vias, or all selected pins and vias.
2032 The second argument specifies the style of connection.
2033 There are 5 possibilities:
2035 1 - 45 degree fingers with sharp edges,
2036 2 - horizontal & vertical fingers with sharp edges,
2037 3 - solid connection,
2038 4 - 45 degree fingers with rounded corners,
2039 5 - horizontal & vertical fingers with rounded corners.
2041 Pins and Vias may have thermals whether or not there is a polygon available
2042 to connect with. However, they will have no effect without the polygon.
2046 ActionSetThermal (int argc
, char **argv
, Coord x
, Coord y
)
2048 char *function
= ARG (0);
2049 char *style
= ARG (1);
2050 void *ptr1
, *ptr2
, *ptr3
;
2054 if (function
&& *function
&& style
&& *style
)
2058 kind
= GetValue (style
, NULL
, &absolute
);
2060 switch (GetFunctionID (function
))
2064 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGETHERMAL_TYPES
,
2065 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
2067 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, kind
);
2068 IncrementUndoSerialNumber ();
2072 case F_SelectedPins
:
2073 ChangeSelectedThermals (PIN_TYPE
, kind
);
2075 case F_SelectedVias
:
2076 ChangeSelectedThermals (VIA_TYPE
, kind
);
2079 case F_SelectedElements
:
2080 ChangeSelectedThermals (CHANGETHERMAL_TYPES
, kind
);
2095 /* ---------------------------------------------------------------------------
2096 * !!! no action routine !!!
2098 * event handler to set the cursor according to the X pointer position
2099 * called from inside main.c
2102 EventMoveCrosshair (int ev_x
, int ev_y
)
2104 #ifdef HAVE_LIBSTROKE
2107 StrokeBox
.X2
= ev_x
;
2108 StrokeBox
.Y2
= ev_y
;
2109 stroke_record (ev_x
, ev_y
);
2112 #endif /* HAVE_LIBSTROKE */
2113 if (MoveCrosshairAbsolute (ev_x
, ev_y
))
2115 /* update object position and cursor location */
2116 AdjustAttachedObjects ();
2117 notify_crosshair_change (true);
2121 /* --------------------------------------------------------------------------- */
2123 static const char setvalue_syntax
[] =
2124 "SetValue(Grid|Line|LineSize|Text|TextScale|ViaDrillingHole|Via|ViaSize, delta)";
2126 static const char setvalue_help
[] =
2127 "Change various board-wide values and sizes.";
2129 /* %start-doc actions SetValue
2133 @item ViaDrillingHole
2134 Changes the diameter of the drill for new vias.
2137 Sets the grid spacing.
2141 Changes the thickness of new lines.
2145 Changes the diameter of new vias.
2149 Changes the size of new text.
2156 ActionSetValue (int argc
, char **argv
, Coord x
, Coord y
)
2158 char *function
= ARG (0);
2159 char *val
= ARG (1);
2160 char *units
= ARG (2);
2161 bool absolute
; /* flag for 'absolute' value */
2166 if (function
&& val
)
2168 value
= GetValue (val
, units
, &absolute
);
2169 switch (GetFunctionID (function
))
2171 case F_ViaDrillingHole
:
2172 SetViaDrillingHole (absolute
? value
:
2173 value
+ Settings
.ViaDrillingHole
,
2175 hid_action ("RouteStylesChanged");
2180 SetGrid (value
, false);
2184 value
= val
[0] == '-' ? -Settings
.increments
->grid
2185 : Settings
.increments
->grid
;
2186 /* On the way down, short against the minimum
2187 * PCB drawing unit */
2188 if ((value
+ PCB
->Grid
) < 1)
2190 else if (PCB
->Grid
== 1)
2191 SetGrid (value
, false);
2193 SetGrid (value
+ PCB
->Grid
, false);
2199 if (!absolute
&& value
== 0)
2200 value
= val
[0] == '-' ? -Settings
.increments
->line
2201 : Settings
.increments
->line
;
2202 SetLineSize (absolute
? value
: value
+ Settings
.LineThickness
);
2203 hid_action ("RouteStylesChanged");
2208 SetViaSize (absolute
? value
: value
+ Settings
.ViaThickness
, false);
2209 hid_action ("RouteStylesChanged");
2214 text_scale
= value
/ (double)FONT_CAPHEIGHT
* 100.;
2216 text_scale
+= Settings
.TextScale
;
2217 SetTextScale (text_scale
);
2231 /* --------------------------------------------------------------------------- */
2233 static const char quit_syntax
[] = "Quit()";
2235 static const char quit_help
[] = "Quits the application after confirming.";
2237 /* %start-doc actions Quit
2239 If you have unsaved changes, you will be prompted to confirm (or
2240 save) before quitting.
2245 ActionQuit (int argc
, char **argv
, Coord x
, Coord y
)
2247 char *force
= ARG (0);
2248 if (force
&& strcasecmp (force
, "force") == 0)
2253 if (!PCB
->Changed
|| gui
->close_confirm_dialog () == HID_CLOSE_CONFIRM_OK
)
2258 /* --------------------------------------------------------------------------- */
2260 static const char connection_syntax
[] =
2261 "Connection(Find|ResetLinesAndPolygons|ResetPinsAndVias|Reset)";
2263 static const char connection_help
[] =
2264 "Searches connections of the object at the cursor position.";
2266 /* %start-doc actions Connection
2268 Connections found with this action will be highlighted in the
2269 ``connected-color'' color and will have the ``found'' flag set.
2274 The net under the cursor is ``found''.
2276 @item ResetLinesAndPolygons
2277 Any ``found'' lines and polygons are marked ``not found''.
2279 @item ResetPinsAndVias
2280 Any ``found'' pins and vias are marked ``not found''.
2283 All ``found'' objects are marked ``not found''.
2290 ActionConnection (int argc
, char **argv
, Coord x
, Coord y
)
2292 char *function
= ARG (0);
2295 switch (GetFunctionID (function
))
2299 gui
->get_coords (_("Click on a connection"), &x
, &y
);
2300 LookupConnection (x
, y
, true, 1, CONNECTEDFLAG
, false);
2301 LookupConnection (x
, y
, true, 1, FOUNDFLAG
, true);
2305 case F_ResetLinesAndPolygons
:
2306 if (ClearFlagOnLinesAndPolygons (true, CONNECTEDFLAG
| FOUNDFLAG
))
2308 IncrementUndoSerialNumber ();
2313 case F_ResetPinsViasAndPads
:
2314 if (ClearFlagOnPinsViasAndPads (true, CONNECTEDFLAG
| FOUNDFLAG
))
2316 IncrementUndoSerialNumber ();
2322 if (ClearFlagOnAllObjects (true, CONNECTEDFLAG
| FOUNDFLAG
))
2324 IncrementUndoSerialNumber ();
2335 /* --------------------------------------------------------------------------- */
2337 static const char disperseelements_syntax
[] =
2338 "DisperseElements(All|Selected)";
2340 static const char disperseelements_help
[] = "Disperses elements.";
2342 /* %start-doc actions DisperseElements
2344 Normally this is used when starting a board, by selecting all elements
2345 and then dispersing them. This scatters the elements around the board
2346 so that you can pick individual ones, rather than have all the
2347 elements at the same 0,0 coordinate and thus impossible to choose
2352 #define GAP MIL_TO_COORD(100)
2355 ActionDisperseElements (int argc
, char **argv
, Coord x
, Coord y
)
2357 char *function
= ARG (0);
2362 int all
= 0, bad
= 0;
2364 if (!function
|| !*function
)
2370 switch (GetFunctionID (function
))
2387 AFAIL (disperseelements
);
2391 ELEMENT_LOOP (PCB
->Data
);
2394 * If we want to disperse selected elements, maybe we need smarter
2395 * code here to avoid putting components on top of others which
2396 * are not selected. For now, I'm assuming that this is typically
2397 * going to be used either with a brand new design or a scratch
2398 * design holding some new components
2400 if (!TEST_FLAG (LOCKFLAG
, element
) && (all
|| TEST_FLAG (SELECTEDFLAG
, element
)))
2403 /* figure out how much to move the element */
2404 dx
= minx
- element
->BoundingBox
.X1
;
2406 /* snap to the grid */
2407 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2410 * and add one grid size so we make sure we always space by GAP or
2415 /* Figure out if this row has room. If not, start a new row */
2416 if (GAP
+ element
->BoundingBox
.X2
+ dx
> PCB
->MaxWidth
)
2422 /* figure out how much to move the element */
2423 dx
= minx
- element
->BoundingBox
.X1
;
2424 dy
= miny
- element
->BoundingBox
.Y1
;
2426 /* snap to the grid */
2427 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2429 dy
-= (element
->MarkY
+ dy
) % PCB
->Grid
;
2432 /* move the element */
2433 MoveElementLowLevel (PCB
->Data
, element
, dx
, dy
);
2435 /* and add to the undo list so we can undo this operation */
2436 AddObjectToMoveUndoList (ELEMENT_TYPE
, NULL
, NULL
, element
, dx
, dy
);
2438 /* keep track of how tall this row is */
2439 minx
+= element
->BoundingBox
.X2
- element
->BoundingBox
.X1
+ GAP
;
2440 if (maxy
< element
->BoundingBox
.Y2
)
2442 maxy
= element
->BoundingBox
.Y2
;
2449 /* done with our action so increment the undo # */
2450 IncrementUndoSerialNumber ();
2453 SetChangedFlag (true);
2460 /* --------------------------------------------------------------------------- */
2462 static const char display_syntax
[] =
2463 "Display(NameOnPCB|Description|Value)\n"
2464 "Display(Grid|Redraw)\n"
2465 "Display(CycleClip|CycleCrosshair|Toggle45Degree|ToggleStartDirection)\n"
2466 "Display(ToggleGrid|ToggleRubberBandMode|ToggleUniqueNames)\n"
2467 "Display(ToggleMask|ToggleName|ToggleClearLine|ToggleFullPoly|ToggleSnapPin)\n"
2468 "Display(ToggleThindraw|ToggleThindrawPoly|ToggleOrthoMove|ToggleLocalRef)\n"
2469 "Display(ToggleCheckPlanes|ToggleShowDRC|ToggleAutoDRC)\n"
2470 "Display(ToggleLiveRoute|LockNames|OnlyNames)\n"
2471 "Display(Pinout|PinOrPadName)";
2473 static const char display_help
[] = "Several display-related actions.";
2475 /* %start-doc actions Display
2482 Specify whether all elements show their name, description, or value.
2485 Redraw the whole board.
2487 @item Toggle45Degree
2488 When clear, lines can be drawn at any angle. When set, lines are
2489 restricted to multiples of 45 degrees and requested lines may be
2490 broken up according to the clip setting.
2493 Changes the way lines are restricted to 45 degree increments. The
2494 various settings are: straight only, orthogonal then angled, and angled
2495 then orthogonal. If AllDirections is set, this action disables it.
2497 @item CycleCrosshair
2498 Changes crosshair drawing. Crosshair may accept form of 4-ray,
2499 8-ray and 12-ray cross.
2501 @item ToggleRubberBandMode
2502 If set, moving an object moves all the lines attached to it too.
2504 @item ToggleStartDirection
2505 If set, each time you set a point in a line, the Clip toggles between
2506 orth-angle and angle-ortho.
2508 @item ToggleUniqueNames
2509 If set, you will not be permitted to change the name of an element to
2510 match that of another element.
2513 If set, pin centers and pad end points are treated as additional grid
2514 points that the cursor can snap to.
2516 @item ToggleLocalRef
2517 If set, the mark is automatically set to the beginning of any move, so
2518 you can see the relative distance you've moved.
2520 @item ToggleThindraw
2521 If set, objects on the screen are drawn as outlines (lines are drawn
2522 as center-lines). This lets you see line endpoints hidden under pins,
2525 @item ToggleThindrawPoly
2526 If set, polygons on the screen are drawn as outlines.
2529 If set, pending objects (i.e. lines you're in the process of drawing)
2530 will be drawn with an outline showing how far away from other copper
2533 @item ToggleLiveRoute
2534 If set, the progress of the autorouter will be visible on the screen.
2537 If set, you will not be permitted to make connections which violate
2538 the current DRC and netlist settings.
2540 @item ToggleCheckPlanes
2541 If set, lines and arcs aren't drawn, which usually leaves just the
2542 polygons. If you also disable all but the layer you're interested in,
2543 this allows you to check for isolated regions.
2545 @item ToggleOrthoMove
2546 If set, the crosshair is only allowed to move orthogonally from its
2547 previous position. I.e. you can move an element or line up, down,
2548 left, or right, but not up+left or down+right.
2551 Selects whether the pinouts show the pin names or the pin numbers.
2553 @item ToggleLockNames
2554 If set, text will ignore left mouse clicks and actions that work on
2555 objects under the mouse. You can still select text with a lasso (left
2556 mouse drag) and perform actions on the selection.
2558 @item ToggleOnlyNames
2559 If set, only text will be sensitive for mouse clicks and actions that
2560 work on objects under the mouse. You can still select other objects
2561 with a lasso (left mouse drag) and perform actions on the selection.
2564 Turns the solder mask on or off.
2566 @item ToggleClearLine
2567 When set, the clear-line flag causes new lines and arcs to have their
2568 ``clear polygons'' flag set, so they won't be electrically connected
2569 to any polygons they overlap.
2571 @item ToggleFullPoly
2572 When set, the full-poly flag causes new polygons to have their
2573 ``full polygon'' flag set, so all parts of them will be displayed
2574 instead of only the biggest one.
2577 Resets the origin of the current grid to be wherever the mouse pointer
2578 is (not where the crosshair currently is). If you provide two numbers
2579 after this, the origin is set to that coordinate.
2582 Toggles whether the grid is displayed or not.
2585 Causes the pinout of the element indicated by the cursor to be
2586 displayed, usually in a separate window.
2589 Toggles whether the names of pins, pads, or (yes) vias will be
2590 displayed. If the cursor is over an element, all of its pins and pads
2597 static enum crosshair_shape
2598 CrosshairShapeIncrement (enum crosshair_shape shape
)
2602 case Basic_Crosshair_Shape
:
2603 shape
= Union_Jack_Crosshair_Shape
;
2605 case Union_Jack_Crosshair_Shape
:
2606 shape
= Dozen_Crosshair_Shape
;
2608 case Dozen_Crosshair_Shape
:
2609 shape
= Crosshair_Shapes_Number
;
2611 case Crosshair_Shapes_Number
:
2612 shape
= Basic_Crosshair_Shape
;
2619 ActionDisplay (int argc
, char **argv
, Coord childX
, Coord childY
)
2621 char *function
, *str_dir
;
2628 if (function
&& (!str_dir
|| !*str_dir
))
2630 switch (id
= GetFunctionID (function
))
2634 case F_ClearAndRedraw
:
2639 /* change the displayed name of elements */
2643 ELEMENT_LOOP (PCB
->Data
);
2645 EraseElementName (element
);
2648 CLEAR_FLAG (DESCRIPTIONFLAG
| NAMEONPCBFLAG
, PCB
);
2654 SET_FLAG (NAMEONPCBFLAG
, PCB
);
2657 SET_FLAG (DESCRIPTIONFLAG
, PCB
);
2660 ELEMENT_LOOP (PCB
->Data
);
2662 DrawElementName (element
);
2668 /* toggle line-adjust flag */
2669 case F_ToggleAllDirections
:
2670 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2671 AdjustAttachedObjects ();
2675 notify_crosshair_change (false);
2676 if (TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
2678 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2682 PCB
->Clipping
= (PCB
->Clipping
+ 1) % 3;
2683 AdjustAttachedObjects ();
2684 notify_crosshair_change (true);
2687 case F_CycleCrosshair
:
2688 notify_crosshair_change (false);
2689 Crosshair
.shape
= CrosshairShapeIncrement(Crosshair
.shape
);
2690 if (Crosshair_Shapes_Number
== Crosshair
.shape
)
2691 Crosshair
.shape
= Basic_Crosshair_Shape
;
2692 notify_crosshair_change (true);
2695 case F_ToggleRubberBandMode
:
2696 notify_crosshair_change (false);
2697 TOGGLE_FLAG (RUBBERBANDFLAG
, PCB
);
2698 notify_crosshair_change (true);
2701 case F_ToggleStartDirection
:
2702 notify_crosshair_change (false);
2703 TOGGLE_FLAG (SWAPSTARTDIRFLAG
, PCB
);
2704 notify_crosshair_change (true);
2707 case F_ToggleUniqueNames
:
2708 TOGGLE_FLAG (UNIQUENAMEFLAG
, PCB
);
2711 case F_ToggleSnapPin
:
2712 notify_crosshair_change (false);
2713 TOGGLE_FLAG (SNAPPINFLAG
, PCB
);
2714 notify_crosshair_change (true);
2717 case F_ToggleLocalRef
:
2718 TOGGLE_FLAG (LOCALREFFLAG
, PCB
);
2721 case F_ToggleThindraw
:
2722 TOGGLE_FLAG (THINDRAWFLAG
, PCB
);
2726 case F_ToggleThindrawPoly
:
2727 TOGGLE_FLAG (THINDRAWPOLYFLAG
, PCB
);
2731 case F_ToggleLockNames
:
2732 TOGGLE_FLAG (LOCKNAMESFLAG
, PCB
);
2733 CLEAR_FLAG (ONLYNAMESFLAG
, PCB
);
2736 case F_ToggleOnlyNames
:
2737 TOGGLE_FLAG (ONLYNAMESFLAG
, PCB
);
2738 CLEAR_FLAG (LOCKNAMESFLAG
, PCB
);
2741 case F_ToggleHideNames
:
2742 TOGGLE_FLAG (HIDENAMESFLAG
, PCB
);
2746 case F_ToggleShowDRC
:
2747 TOGGLE_FLAG (SHOWDRCFLAG
, PCB
);
2750 case F_ToggleLiveRoute
:
2751 TOGGLE_FLAG (LIVEROUTEFLAG
, PCB
);
2754 case F_ToggleAutoDRC
:
2755 notify_crosshair_change (false);
2756 TOGGLE_FLAG (AUTODRCFLAG
, PCB
);
2757 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
2759 if (ClearFlagOnAllObjects (true, CONNECTEDFLAG
| FOUNDFLAG
))
2761 IncrementUndoSerialNumber ();
2764 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
2766 LookupConnection (Crosshair
.AttachedLine
.Point1
.X
,
2767 Crosshair
.AttachedLine
.Point1
.Y
,
2768 true, 1, CONNECTEDFLAG
, false);
2769 LookupConnection (Crosshair
.AttachedLine
.Point1
.X
,
2770 Crosshair
.AttachedLine
.Point1
.Y
,
2771 true, 1, FOUNDFLAG
, true);
2774 notify_crosshair_change (true);
2777 case F_ToggleCheckPlanes
:
2778 TOGGLE_FLAG (CHECKPLANESFLAG
, PCB
);
2782 case F_ToggleOrthoMove
:
2783 TOGGLE_FLAG (ORTHOMOVEFLAG
, PCB
);
2787 TOGGLE_FLAG (SHOWNUMBERFLAG
, PCB
);
2792 TOGGLE_FLAG (SHOWMASKFLAG
, PCB
);
2796 case F_ToggleClearLine
:
2797 TOGGLE_FLAG (CLEARNEWFLAG
, PCB
);
2800 case F_ToggleFullPoly
:
2801 TOGGLE_FLAG (NEWFULLPOLYFLAG
, PCB
);
2804 /* shift grid alignment */
2807 Coord oldGrid
= PCB
->Grid
;
2810 if (MoveCrosshairAbsolute (Crosshair
.X
, Crosshair
.Y
))
2811 notify_crosshair_change (true); /* first notify was in MoveCrosshairAbs */
2812 SetGrid (oldGrid
, true);
2816 /* toggle displaying of the grid */
2818 Settings
.DrawGrid
= !Settings
.DrawGrid
;
2822 /* display the pinout of an element */
2825 ElementType
*element
;
2829 gui
->get_coords (_("Click on an element"), &x
, &y
);
2831 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
2832 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
2834 element
= (ElementType
*) ptrtmp
;
2835 gui
->show_item (element
);
2840 /* toggle displaying of pin/pad/via names */
2841 case F_PinOrPadName
:
2843 void *ptr1
, *ptr2
, *ptr3
;
2845 switch (SearchScreen (Crosshair
.X
, Crosshair
.Y
,
2846 ELEMENT_TYPE
| PIN_TYPE
| PAD_TYPE
|
2847 VIA_TYPE
, (void **) &ptr1
, (void **) &ptr2
,
2851 PIN_LOOP ((ElementType
*) ptr1
);
2853 if (TEST_FLAG (DISPLAYNAMEFLAG
, pin
))
2857 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, pin
, pin
);
2858 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pin
);
2861 PAD_LOOP ((ElementType
*) ptr1
);
2863 if (TEST_FLAG (DISPLAYNAMEFLAG
, pad
))
2867 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, pad
, pad
);
2868 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pad
);
2871 SetChangedFlag (true);
2872 IncrementUndoSerialNumber ();
2877 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
))
2878 ErasePinName ((PinType
*) ptr2
);
2880 DrawPinName ((PinType
*) ptr2
);
2881 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, ptr2
, ptr3
);
2882 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
);
2883 SetChangedFlag (true);
2884 IncrementUndoSerialNumber ();
2889 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PadType
*) ptr2
))
2890 ErasePadName ((PadType
*) ptr2
);
2892 DrawPadName ((PadType
*) ptr2
);
2893 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, ptr2
, ptr3
);
2894 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PadType
*) ptr2
);
2895 SetChangedFlag (true);
2896 IncrementUndoSerialNumber ();
2900 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
))
2901 EraseViaName ((PinType
*) ptr2
);
2903 DrawViaName ((PinType
*) ptr2
);
2904 AddObjectToFlagUndoList (VIA_TYPE
, ptr1
, ptr2
, ptr3
);
2905 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
);
2906 SetChangedFlag (true);
2907 IncrementUndoSerialNumber ();
2917 else if (function
&& str_dir
)
2919 switch (GetFunctionID (function
))
2924 PCB
->GridOffsetX
= GetValue (argv
[1], NULL
, NULL
);
2925 PCB
->GridOffsetY
= GetValue (argv
[2], NULL
, NULL
);
2926 if (Settings
.DrawGrid
)
2943 /* --------------------------------------------------------------------------- */
2945 static const char mode_syntax
[] =
2946 "Mode(Arc|Arrow|Copy|InsertPoint|Line|Lock|Move|None|PasteBuffer)\n"
2947 "Mode(Polygon|Rectangle|Remove|Rotate|Text|Thermal|Via)\n"
2948 "Mode(Notify|Release|Cancel|Stroke)\n"
2949 "Mode(Save|Restore)";
2951 static const char mode_help
[] = "Change or use the tool mode.";
2953 /* %start-doc actions Mode
2973 Select the indicated tool.
2976 Called when you press the mouse button, or move the mouse.
2979 Called when you release the mouse button.
2982 Cancels any pending tool activity, allowing you to restart elsewhere.
2983 For example, this allows you to start a new line rather than attach a
2984 line to the previous line.
2987 Similar to Cancel but calling this action a second time will return
2991 If your @code{pcb} was built with libstroke, this invokes the stroke
2992 input method. If not, this will restart a drawing mode if you were
2993 drawing, else it will select objects.
2996 Remembers the current tool.
2999 Restores the tool to the last saved tool.
3006 ActionMode (int argc
, char **argv
, Coord x
, Coord y
)
3008 char *function
= ARG (0);
3012 Note
.X
= Crosshair
.X
;
3013 Note
.Y
= Crosshair
.Y
;
3014 notify_crosshair_change (false);
3015 switch (GetFunctionID (function
))
3021 SetMode (ARROW_MODE
);
3024 SetMode (COPY_MODE
);
3027 SetMode (INSERTPOINT_MODE
);
3030 SetMode (LINE_MODE
);
3033 SetMode (LOCK_MODE
);
3036 SetMode (MOVE_MODE
);
3043 int saved_mode
= Settings
.Mode
;
3045 SetMode (saved_mode
);
3050 switch (Settings
.Mode
)
3053 case PASTEBUFFER_MODE
:
3059 case INSERTPOINT_MODE
:
3060 case RUBBERBANDMOVE_MODE
:
3064 SetMode (ARROW_MODE
);
3068 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3069 SetMode (ARROW_MODE
);
3073 SetMode (LINE_MODE
);
3077 case RECTANGLE_MODE
:
3078 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3079 SetMode (ARROW_MODE
);
3083 SetMode (RECTANGLE_MODE
);
3088 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3089 SetMode (ARROW_MODE
);
3093 SetMode (POLYGON_MODE
);
3097 case POLYGONHOLE_MODE
:
3098 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3099 SetMode (ARROW_MODE
);
3103 SetMode (POLYGONHOLE_MODE
);
3108 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3109 SetMode (ARROW_MODE
);
3130 SetMode (PASTEBUFFER_MODE
);
3133 SetMode (POLYGON_MODE
);
3136 SetMode (POLYGONHOLE_MODE
);
3138 #ifndef HAVE_LIBSTROKE
3151 SetMode (REMOVE_MODE
);
3154 SetMode (RECTANGLE_MODE
);
3157 SetMode (ROTATE_MODE
);
3160 #ifdef HAVE_LIBSTROKE
3162 StrokeBox
.X1
= Crosshair
.X
;
3163 StrokeBox
.Y1
= Crosshair
.Y
;
3166 /* Handle middle mouse button restarts of drawing mode. If not in
3167 | a drawing mode, middle mouse button will select objects.
3169 if (Settings
.Mode
== LINE_MODE
3170 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3172 SetMode (LINE_MODE
);
3174 else if (Settings
.Mode
== ARC_MODE
3175 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3177 else if (Settings
.Mode
== RECTANGLE_MODE
3178 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3179 SetMode (RECTANGLE_MODE
);
3180 else if (Settings
.Mode
== POLYGON_MODE
3181 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3182 SetMode (POLYGON_MODE
);
3187 SetMode (ARROW_MODE
);
3193 SetMode (TEXT_MODE
);
3196 SetMode (THERMAL_MODE
);
3202 case F_Restore
: /* restore the last saved mode */
3206 case F_Save
: /* save currently selected mode */
3210 notify_crosshair_change (true);
3217 /* --------------------------------------------------------------------------- */
3219 static const char removeselected_syntax
[] = "RemoveSelected()";
3221 static const char removeselected_help
[] = "Removes any selected objects.";
3223 /* %start-doc actions RemoveSelected
3228 ActionRemoveSelected (int argc
, char **argv
, Coord x
, Coord y
)
3230 if (RemoveSelected ())
3231 SetChangedFlag (true);
3235 /* --------------------------------------------------------------------------- */
3237 static const char renumber_syntax
[] = "Renumber()\n"
3238 "Renumber(filename)";
3240 static const char renumber_help
[] =
3241 "Renumber all elements. The changes will be recorded to filename\n"
3242 "for use in backannotating these changes to the schematic.";
3244 /* %start-doc actions Renumber
3249 ActionRenumber (int argc
, char **argv
, Coord x
, Coord y
)
3251 bool changed
= false;
3252 ElementType
**element_list
;
3253 ElementType
**locked_element_list
;
3254 unsigned int i
, j
, k
, cnt
, lock_cnt
;
3260 static char * default_file
= NULL
;
3261 size_t cnt_list_sz
= 100;
3267 char **was
, **is
, *pin
;
3268 unsigned int c_cnt
= 0;
3275 * We deal with the case where name already exists in this
3276 * function so the GUI doesn't need to deal with it
3278 name
= gui
->fileselect (_("Save Renumber Annotation File As ..."),
3279 _("Choose a file to record the renumbering to.\n"
3280 "This file may be used to back annotate the\n"
3281 "change to the schematics.\n"),
3282 default_file
, ".eco", "eco",
3292 free (default_file
);
3293 default_file
= NULL
;
3298 default_file
= strdup (name
);
3301 if ((out
= fopen (name
, "r")))
3304 if (!gui
->confirm_dialog (_("File exists! Ok to overwrite?"), 0))
3306 if (free_name
&& name
)
3312 if ((out
= fopen (name
, "w")) == NULL
)
3314 Message (_("Could not open %s\n"), name
);
3315 if (free_name
&& name
)
3320 if (free_name
&& name
)
3323 fprintf (out
, "*COMMENT* PCB Annotation File\n");
3324 fprintf (out
, "*FILEVERSION* 20061031\n");
3327 * Make a first pass through all of the elements and sort them out
3328 * by location on the board. While here we also collect a list of
3331 * We'll actually renumber things in the 2nd pass.
3333 element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementType
*));
3334 locked_element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementType
*));
3335 was
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3336 is
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3337 if (element_list
== NULL
|| locked_element_list
== NULL
|| was
== NULL
3340 fprintf (stderr
, "calloc() failed in %s\n", __FUNCTION__
);
3347 ELEMENT_LOOP (PCB
->Data
);
3349 if (TEST_FLAG (LOCKFLAG
, element
->Name
) || TEST_FLAG (LOCKFLAG
, element
))
3352 * add to the list of locked elements which we won't try to
3353 * renumber and whose reference designators are now reserved.
3356 "*WARN* Element \"%s\" at %$md is locked and will not be renumbered.\n",
3357 UNKNOWN (NAMEONPCB_NAME (element
)), element
->MarkX
, element
->MarkY
);
3358 locked_element_list
[lock_cnt
] = element
;
3364 /* count of devices which will be renumbered */
3367 /* search for correct position in the list */
3369 while (element_list
[i
] && element
->MarkY
> element_list
[i
]->MarkY
)
3373 * We have found the position where we have the first element that
3374 * has the same Y value or a lower Y value. Now move forward if
3375 * needed through the X values
3377 while (element_list
[i
]
3378 && element
->MarkY
== element_list
[i
]->MarkY
3379 && element
->MarkX
> element_list
[i
]->MarkX
)
3382 for (j
= cnt
- 1; j
> i
; j
--)
3384 element_list
[j
] = element_list
[j
- 1];
3386 element_list
[i
] = element
;
3393 * Now that the elements are sorted by board position, we go through
3394 * and renumber them.
3398 * turn off the flag which requires unique names so it doesn't get
3399 * in our way. When we're done with the renumber we will have unique
3402 unique
= TEST_FLAG (UNIQUENAMEFLAG
, PCB
);
3403 CLEAR_FLAG (UNIQUENAMEFLAG
, PCB
);
3405 cnt_list
= (struct _cnt_list
*)calloc (cnt_list_sz
, sizeof (struct _cnt_list
));
3406 for (i
= 0; i
< cnt
; i
++)
3408 /* If there is no refdes, maybe just spit out a warning */
3409 if (NAMEONPCB_NAME (element_list
[i
]))
3411 /* figure out the prefix */
3412 tmps
= strdup (NAMEONPCB_NAME (element_list
[i
]));
3414 while (tmps
[j
] && (tmps
[j
] < '0' || tmps
[j
] > '9')
3419 /* check the counter for this prefix */
3421 cnt_list
[j
].name
&& (strcmp (cnt_list
[j
].name
, tmps
) != 0)
3422 && j
< cnt_list_sz
; j
++);
3424 /* grow the list if needed */
3425 if (j
== cnt_list_sz
)
3428 cnt_list
= (struct _cnt_list
*)realloc (cnt_list
, cnt_list_sz
);
3429 if (cnt_list
== NULL
)
3431 fprintf (stderr
, "realloc failed() in %s\n", __FUNCTION__
);
3434 /* zero out the memory that we added */
3435 for (tmpi
= j
; tmpi
< cnt_list_sz
; tmpi
++)
3437 cnt_list
[tmpi
].name
= NULL
;
3438 cnt_list
[tmpi
].cnt
= 0;
3443 * start a new counter if we don't have a counter for this
3446 if (!cnt_list
[j
].name
)
3448 cnt_list
[j
].name
= strdup (tmps
);
3449 cnt_list
[j
].cnt
= 0;
3453 * check to see if the new refdes is already used by a
3462 /* space for the prefix plus 1 digit plus the '\0' */
3463 sz
= strlen (cnt_list
[j
].name
) + 2;
3465 /* and 1 more per extra digit needed to hold the number */
3466 tmpi
= cnt_list
[j
].cnt
;
3472 tmps
= (char *)malloc (sz
* sizeof (char));
3473 sprintf (tmps
, "%s%d", cnt_list
[j
].name
, cnt_list
[j
].cnt
);
3476 * now compare to the list of reserved (by locked
3479 for (k
= 0; k
< lock_cnt
; k
++)
3482 (UNKNOWN (NAMEONPCB_NAME (locked_element_list
[k
])),
3493 if (strcmp (tmps
, NAMEONPCB_NAME (element_list
[i
])) != 0)
3495 fprintf (out
, "*RENAME* \"%s\" \"%s\"\n",
3496 NAMEONPCB_NAME (element_list
[i
]), tmps
);
3498 /* add this rename to our table of renames so we can update the netlist */
3499 was
[c_cnt
] = strdup (NAMEONPCB_NAME (element_list
[i
]));
3500 is
[c_cnt
] = strdup (tmps
);
3503 AddObjectToChangeNameUndoList (ELEMENT_TYPE
, NULL
, NULL
,
3505 NAMEONPCB_NAME (element_list
3508 ChangeObjectName (ELEMENT_TYPE
, element_list
[i
], NULL
, NULL
,
3512 /* we don't free tmps in this case because it is used */
3519 pcb_fprintf (out
, "*WARN* Element at %$md has no name.\n",
3520 element_list
[i
]->MarkX
, element_list
[i
]->MarkY
);
3527 /* restore the unique flag setting */
3529 SET_FLAG (UNIQUENAMEFLAG
, PCB
);
3534 /* update the netlist */
3535 AddNetlistLibToUndoList (&(PCB
->NetlistLib
));
3537 /* iterate over each net */
3538 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
3541 /* iterate over each pin on the net */
3542 for (j
= 0; j
< PCB
->NetlistLib
.Menu
[i
].EntryN
; j
++)
3545 /* figure out the pin number part from strings like U3-21 */
3546 tmps
= strdup (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3547 for (k
= 0; tmps
[k
] && tmps
[k
] != '-'; k
++);
3551 /* iterate over the list of changed reference designators */
3552 for (k
= 0; k
< c_cnt
; k
++)
3555 * if the pin needs to change, change it and quit
3556 * searching in the list.
3558 if (strcmp (tmps
, was
[k
]) == 0)
3560 free (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3561 PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
=
3562 (char *)malloc ((strlen (is
[k
]) + strlen (pin
) +
3563 2) * sizeof (char));
3564 sprintf (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
,
3565 "%s-%s", is
[k
], pin
);
3573 for (k
= 0; k
< c_cnt
; k
++)
3580 IncrementUndoSerialNumber ();
3581 SetChangedFlag (true);
3584 free (locked_element_list
);
3585 free (element_list
);
3591 /* --------------------------------------------------------------------------- */
3593 static const char ripup_syntax
[] = "RipUp(All|Selected|Element)";
3595 static const char ripup_help
[] =
3596 "Ripup auto-routed tracks, or convert an element to parts.";
3598 /* %start-doc actions RipUp
3603 Removes all lines and vias which were created by the autorouter.
3606 Removes all selected lines and vias which were created by the
3610 Converts the element under the cursor to parts (vias and lines). Note
3611 that this uses the highest numbered paste buffer.
3618 ActionRipUp (int argc
, char **argv
, Coord x
, Coord y
)
3620 char *function
= ARG (0);
3621 bool changed
= false;
3625 switch (GetFunctionID (function
))
3628 ALLLINE_LOOP (PCB
->Data
);
3630 if (TEST_FLAG (AUTOFLAG
, line
) && !TEST_FLAG (LOCKFLAG
, line
))
3632 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3637 ALLARC_LOOP (PCB
->Data
);
3639 if (TEST_FLAG (AUTOFLAG
, arc
) && !TEST_FLAG (LOCKFLAG
, arc
))
3641 RemoveObject (ARC_TYPE
, layer
, arc
, arc
);
3646 VIA_LOOP (PCB
->Data
);
3648 if (TEST_FLAG (AUTOFLAG
, via
) && !TEST_FLAG (LOCKFLAG
, via
))
3650 RemoveObject (VIA_TYPE
, via
, via
, via
);
3658 IncrementUndoSerialNumber ();
3659 SetChangedFlag (true);
3663 VISIBLELINE_LOOP (PCB
->Data
);
3665 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, line
)
3666 && !TEST_FLAG (LOCKFLAG
, line
))
3668 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3674 VIA_LOOP (PCB
->Data
);
3676 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, via
)
3677 && !TEST_FLAG (LOCKFLAG
, via
))
3679 RemoveObject (VIA_TYPE
, via
, via
, via
);
3686 IncrementUndoSerialNumber ();
3687 SetChangedFlag (true);
3692 void *ptr1
, *ptr2
, *ptr3
;
3694 if (SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
3695 &ptr1
, &ptr2
, &ptr3
) != NO_TYPE
)
3697 Note
.Buffer
= Settings
.BufferNumber
;
3698 SetBufferNumber (MAX_BUFFER
- 1);
3699 ClearBuffer (PASTEBUFFER
);
3700 CopyObjectToBuffer (PASTEBUFFER
->Data
, PCB
->Data
,
3701 ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3702 SmashBufferElement (PASTEBUFFER
);
3705 SaveUndoSerialNumber ();
3706 EraseObject (ELEMENT_TYPE
, ptr1
, ptr1
);
3707 MoveObjectToRemoveUndoList (ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3708 RestoreUndoSerialNumber ();
3709 CopyPastebufferToLayout (0, 0);
3710 SetBufferNumber (Note
.Buffer
);
3711 SetChangedFlag (true);
3720 /* --------------------------------------------------------------------------- */
3722 static const char addrats_syntax
[] = "AddRats(AllRats|SelectedRats|Close)";
3724 static const char addrats_help
[] = "Add one or more rat lines to the board.";
3726 /* %start-doc actions AddRats
3731 Create rat lines for all loaded nets that aren't already connected on
3735 Similarly, but only add rat lines for nets connected to selected pins
3739 Selects the shortest unselected rat on the board.
3746 ActionAddRats (int argc
, char **argv
, Coord x
, Coord y
)
3748 char *function
= ARG (0);
3754 if (Settings
.RatWarn
)
3756 switch (GetFunctionID (function
))
3759 if (AddAllRats (false, NULL
))
3760 SetChangedFlag (true);
3762 case F_SelectedRats
:
3764 if (AddAllRats (true, NULL
))
3765 SetChangedFlag (true);
3768 small
= SQUARE (MAX_COORD
);
3770 RAT_LOOP (PCB
->Data
);
3772 if (TEST_FLAG (SELECTEDFLAG
, line
))
3774 len
= SQUARE (line
->Point1
.X
- line
->Point2
.X
) +
3775 SQUARE (line
->Point1
.Y
- line
->Point2
.Y
);
3785 AddObjectToFlagUndoList (RATLINE_TYPE
, shorty
, shorty
, shorty
);
3786 SET_FLAG (SELECTEDFLAG
, shorty
);
3789 CenterDisplay ((shorty
->Point2
.X
+ shorty
->Point1
.X
) / 2,
3790 (shorty
->Point2
.Y
+ shorty
->Point1
.Y
) / 2);
3798 /* --------------------------------------------------------------------------- */
3800 static const char delete_syntax
[] =
3801 "Delete(Object|Selected)\n"
3802 "Delete(AllRats|SelectedRats)";
3804 static const char delete_help
[] = "Delete stuff.";
3806 /* %start-doc actions Delete
3811 ActionDelete (int argc
, char **argv
, Coord x
, Coord y
)
3813 char *function
= ARG (0);
3814 int id
= GetFunctionID (function
);
3816 Note
.X
= Crosshair
.X
;
3817 Note
.Y
= Crosshair
.Y
;
3819 if (id
== -1) /* no arg */
3821 if (RemoveSelected() == false)
3829 SetMode(REMOVE_MODE
);
3837 if (DeleteRats (false))
3838 SetChangedFlag (true);
3840 case F_SelectedRats
:
3841 if (DeleteRats (true))
3842 SetChangedFlag (true);
3849 /* --------------------------------------------------------------------------- */
3851 static const char deleterats_syntax
[] =
3852 "DeleteRats(AllRats|Selected|SelectedRats)";
3854 static const char deleterats_help
[] = "Delete rat lines.";
3856 /* %start-doc actions DeleteRats
3861 ActionDeleteRats (int argc
, char **argv
, Coord x
, Coord y
)
3863 char *function
= ARG (0);
3866 if (Settings
.RatWarn
)
3868 switch (GetFunctionID (function
))
3871 if (DeleteRats (false))
3872 SetChangedFlag (true);
3874 case F_SelectedRats
:
3876 if (DeleteRats (true))
3877 SetChangedFlag (true);
3884 /* --------------------------------------------------------------------------- */
3886 static const char autoplace_syntax
[] = "AutoPlaceSelected()";
3888 static const char autoplace_help
[] = "Auto-place selected components.";
3890 /* %start-doc actions AutoPlaceSelected
3892 Attempts to re-arrange the selected components such that the nets
3893 connecting them are minimized. Note that you cannot undo this.
3898 ActionAutoPlaceSelected (int argc
, char **argv
, Coord x
, Coord y
)
3901 if (gui
->confirm_dialog (_("Auto-placement can NOT be undone.\n"
3902 "Do you want to continue anyway?\n"), 0))
3904 if (AutoPlaceSelected ())
3905 SetChangedFlag (true);
3910 /* --------------------------------------------------------------------------- */
3912 static const char autoroute_syntax
[] = "AutoRoute(AllRats|SelectedRats)";
3914 static const char autoroute_help
[] = "Auto-route some or all rat lines.";
3916 /* %start-doc actions AutoRoute
3921 Attempt to autoroute all rats.
3924 Attempt to autoroute the selected rats.
3928 Before autorouting, it's important to set up a few things. First,
3929 make sure any layers you aren't using are disabled, else the
3930 autorouter may use them. Next, make sure the current line and via
3931 styles are set accordingly. Last, make sure "new lines clear
3932 polygons" is set, in case you eventually want to add a copper pour.
3934 Autorouting takes a while. During this time, the program may not be
3940 ActionAutoRoute (int argc
, char **argv
, Coord x
, Coord y
)
3942 char *function
= ARG (0);
3944 if (function
) /* one parameter */
3946 switch (GetFunctionID (function
))
3949 if (AutoRoute (false))
3950 SetChangedFlag (true);
3952 case F_SelectedRats
:
3954 if (AutoRoute (true))
3955 SetChangedFlag (true);
3962 /* --------------------------------------------------------------------------- */
3964 static const char markcrosshair_syntax
[] =
3966 "MarkCrosshair(Center)";
3968 static const char markcrosshair_help
[] = "Set/Reset the Crosshair mark.";
3970 /* %start-doc actions MarkCrosshair
3972 The ``mark'' is a small X-shaped target on the display which is
3973 treated like a second origin (the normal origin is the upper let
3974 corner of the board). The GUI will display a second set of
3975 coordinates for this mark, which tells you how far you are from it.
3977 If no argument is given, the mark is toggled - disabled if it was
3978 enabled, or enabled at the current cursor position of disabled. If
3979 the @code{Center} argument is given, the mark is moved to the current
3985 ActionMarkCrosshair (int argc
, char **argv
, Coord x
, Coord y
)
3987 char *function
= ARG (0);
3988 if (!function
|| !*function
)
3992 notify_mark_change (false);
3993 Marked
.status
= false;
3994 notify_mark_change (true);
3998 notify_mark_change (false);
3999 Marked
.status
= false;
4000 Marked
.status
= true;
4001 Marked
.X
= Crosshair
.X
;
4002 Marked
.Y
= Crosshair
.Y
;
4003 notify_mark_change (true);
4006 else if (GetFunctionID (function
) == F_Center
)
4008 notify_mark_change (false);
4009 Marked
.status
= true;
4010 Marked
.X
= Crosshair
.X
;
4011 Marked
.Y
= Crosshair
.Y
;
4012 notify_mark_change (true);
4017 /* --------------------------------------------------------------------------- */
4019 static const char changesize_syntax
[] =
4020 "ChangeSize(Object, delta)\n"
4021 "ChangeSize(SelectedObjects|Selected, delta)\n"
4022 "ChangeSize(SelectedLines|SelectedPins|SelectedVias, delta)\n"
4023 "ChangeSize(SelectedPads|SelectedTexts|SelectedNames, delta)\n"
4024 "ChangeSize(SelectedElements, delta)";
4026 static const char changesize_help
[] = "Changes the size of objects.";
4028 /* %start-doc actions ChangeSize
4030 For lines and arcs, this changes the width. For pins and vias, this
4031 changes the overall diameter of the copper annulus. For pads, this
4032 changes the width and, indirectly, the length. For texts and names,
4033 this changes the scaling factor. For elements, this changes the width
4034 of the silk layer lines and arcs for this element.
4039 ActionChangeSize (int argc
, char **argv
, Coord x
, Coord y
)
4041 char *function
= ARG (0);
4042 char *delta
= ARG (1);
4043 char *units
= ARG (2);
4044 bool absolute
; /* indicates if absolute size is given */
4047 if (function
&& delta
)
4049 value
= GetValue (delta
, units
, &absolute
);
4051 value
= delta
[0] == '-' ? -Settings
.increments
->size
4052 : Settings
.increments
->size
;
4053 switch (GetFunctionID (function
))
4058 void *ptr1
, *ptr2
, *ptr3
;
4061 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
4062 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4063 if (TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
4064 Message (_("Sorry, the object is locked\n"));
4065 if (ChangeObjectSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4066 SetChangedFlag (true);
4070 case F_SelectedVias
:
4071 if (ChangeSelectedSize (VIA_TYPE
, value
, absolute
))
4072 SetChangedFlag (true);
4075 case F_SelectedPins
:
4076 if (ChangeSelectedSize (PIN_TYPE
, value
, absolute
))
4077 SetChangedFlag (true);
4080 case F_SelectedPads
:
4081 if (ChangeSelectedSize (PAD_TYPE
, value
, absolute
))
4082 SetChangedFlag (true);
4085 case F_SelectedArcs
:
4086 if (ChangeSelectedSize (ARC_TYPE
, value
, absolute
))
4087 SetChangedFlag (true);
4090 case F_SelectedLines
:
4091 if (ChangeSelectedSize (LINE_TYPE
, value
, absolute
))
4092 SetChangedFlag (true);
4095 case F_SelectedTexts
:
4096 if (ChangeSelectedSize (TEXT_TYPE
, value
, absolute
))
4097 SetChangedFlag (true);
4100 case F_SelectedNames
:
4101 if (ChangeSelectedSize (ELEMENTNAME_TYPE
, value
, absolute
))
4102 SetChangedFlag (true);
4105 case F_SelectedElements
:
4106 if (ChangeSelectedSize (ELEMENT_TYPE
, value
, absolute
))
4107 SetChangedFlag (true);
4111 case F_SelectedObjects
:
4112 if (ChangeSelectedSize (CHANGESIZE_TYPES
, value
, absolute
))
4113 SetChangedFlag (true);
4120 /* --------------------------------------------------------------------------- */
4122 static const char changedrillsize_syntax
[] =
4123 "ChangeDrillSize(Object, delta)\n"
4124 "ChangeDrillSize(SelectedPins|SelectedVias|Selected|SelectedObjects, delta)";
4126 static const char changedrillsize_help
[] =
4127 "Changes the drilling hole size of objects.";
4129 /* %start-doc actions ChangeDrillSize
4134 ActionChange2ndSize (int argc
, char **argv
, Coord x
, Coord y
)
4136 char *function
= ARG (0);
4137 char *delta
= ARG (1);
4138 char *units
= ARG (2);
4142 if (function
&& delta
)
4144 value
= GetValue (delta
, units
, &absolute
);
4145 switch (GetFunctionID (function
))
4150 void *ptr1
, *ptr2
, *ptr3
;
4152 gui
->get_coords (_("Select an Object"), &x
, &y
);
4154 SearchScreen (x
, y
, CHANGE2NDSIZE_TYPES
,
4155 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4156 if (ChangeObject2ndSize
4157 (type
, ptr1
, ptr2
, ptr3
, value
, absolute
, true))
4158 SetChangedFlag (true);
4162 case F_SelectedVias
:
4163 if (ChangeSelected2ndSize (VIA_TYPE
, value
, absolute
))
4164 SetChangedFlag (true);
4167 case F_SelectedPins
:
4168 if (ChangeSelected2ndSize (PIN_TYPE
, value
, absolute
))
4169 SetChangedFlag (true);
4172 case F_SelectedObjects
:
4173 if (ChangeSelected2ndSize (PIN_TYPES
, value
, absolute
))
4174 SetChangedFlag (true);
4181 /* --------------------------------------------------------------------------- */
4183 static const char changeclearsize_syntax
[] =
4184 "ChangeClearSize(Object, delta)\n"
4185 "ChangeClearSize(SelectedPins|SelectedPads|SelectedVias, delta)\n"
4186 "ChangeClearSize(SelectedLines|SelectedArcs, delta\n"
4187 "ChangeClearSize(Selected|SelectedObjects, delta)";
4189 static const char changeclearsize_help
[] =
4190 "Changes the clearance size of objects.";
4192 /* %start-doc actions ChangeClearSize
4194 If the solder mask is currently showing, this action changes the
4195 solder mask clearance. If the mask is not showing, this action
4196 changes the polygon clearance.
4201 ActionChangeClearSize (int argc
, char **argv
, Coord x
, Coord y
)
4203 char *function
= ARG (0);
4204 char *delta
= ARG (1);
4205 char *units
= ARG (2);
4209 if (function
&& delta
)
4211 value
= 2 * GetValue (delta
, units
, &absolute
);
4213 value
= delta
[0] == '-' ? -Settings
.increments
->clear
4214 : Settings
.increments
->clear
;
4215 switch (GetFunctionID (function
))
4220 void *ptr1
, *ptr2
, *ptr3
;
4222 gui
->get_coords (_("Select an Object"), &x
, &y
);
4225 CHANGECLEARSIZE_TYPES
, &ptr1
, &ptr2
,
4227 if (ChangeObjectClearSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4228 SetChangedFlag (true);
4231 case F_SelectedVias
:
4232 if (ChangeSelectedClearSize (VIA_TYPE
, value
, absolute
))
4233 SetChangedFlag (true);
4235 case F_SelectedPads
:
4236 if (ChangeSelectedClearSize (PAD_TYPE
, value
, absolute
))
4237 SetChangedFlag (true);
4239 case F_SelectedPins
:
4240 if (ChangeSelectedClearSize (PIN_TYPE
, value
, absolute
))
4241 SetChangedFlag (true);
4243 case F_SelectedLines
:
4244 if (ChangeSelectedClearSize (LINE_TYPE
, value
, absolute
))
4245 SetChangedFlag (true);
4247 case F_SelectedArcs
:
4248 if (ChangeSelectedClearSize (ARC_TYPE
, value
, absolute
))
4249 SetChangedFlag (true);
4252 case F_SelectedObjects
:
4253 if (ChangeSelectedClearSize (CHANGECLEARSIZE_TYPES
, value
, absolute
))
4254 SetChangedFlag (true);
4261 /* --------------------------------------------------------------------------- */
4263 static const char minmaskgap_syntax
[] =
4264 "MinMaskGap(delta)\n"
4265 "MinMaskGap(Selected, delta)";
4267 static const char minmaskgap_help
[] =
4268 "Ensures the mask is a minimum distance from pins and pads.";
4270 /* %start-doc actions MinMaskGap
4272 Checks all specified pins and/or pads, and increases the mask if
4273 needed to ensure a minimum distance between the pin or pad edge and
4279 ActionMinMaskGap (int argc
, char **argv
, Coord x
, Coord y
)
4281 char *function
= ARG (0);
4282 char *delta
= ARG (1);
4283 char *units
= ARG (2);
4290 if (strcasecmp (function
, "Selected") == 0)
4291 flags
= SELECTEDFLAG
;
4298 value
= 2 * GetValue (delta
, units
, &absolute
);
4300 SaveUndoSerialNumber ();
4301 ELEMENT_LOOP (PCB
->Data
);
4305 if (!TEST_FLAGS (flags
, pin
))
4307 if (pin
->Mask
< pin
->Thickness
+ value
)
4309 ChangeObjectMaskSize (PIN_TYPE
, element
, pin
, 0,
4310 pin
->Thickness
+ value
, 1);
4311 RestoreUndoSerialNumber ();
4317 if (!TEST_FLAGS (flags
, pad
))
4319 if (pad
->Mask
< pad
->Thickness
+ value
)
4321 ChangeObjectMaskSize (PAD_TYPE
, element
, pad
, 0,
4322 pad
->Thickness
+ value
, 1);
4323 RestoreUndoSerialNumber ();
4329 VIA_LOOP (PCB
->Data
);
4331 if (!TEST_FLAGS (flags
, via
))
4333 if (via
->Mask
&& via
->Mask
< via
->Thickness
+ value
)
4335 ChangeObjectMaskSize (VIA_TYPE
, via
, 0, 0, via
->Thickness
+ value
, 1);
4336 RestoreUndoSerialNumber ();
4340 RestoreUndoSerialNumber ();
4341 IncrementUndoSerialNumber ();
4345 /* --------------------------------------------------------------------------- */
4347 static const char mincleargap_syntax
[] =
4348 "MinClearGap(delta)\n"
4349 "MinClearGap(Selected, delta)";
4351 static const char mincleargap_help
[] =
4352 "Ensures that polygons are a minimum distance from objects.";
4354 /* %start-doc actions MinClearGap
4356 Checks all specified objects, and increases the polygon clearance if
4357 needed to ensure a minimum distance between their edges and the
4363 ActionMinClearGap (int argc
, char **argv
, Coord x
, Coord y
)
4365 char *function
= ARG (0);
4366 char *delta
= ARG (1);
4367 char *units
= ARG (2);
4374 if (strcasecmp (function
, "Selected") == 0)
4375 flags
= SELECTEDFLAG
;
4382 value
= 2 * GetValue (delta
, units
, &absolute
);
4384 SaveUndoSerialNumber ();
4385 ELEMENT_LOOP (PCB
->Data
);
4389 if (!TEST_FLAGS (flags
, pin
))
4391 if (pin
->Clearance
< value
)
4393 ChangeObjectClearSize (PIN_TYPE
, element
, pin
, 0,
4395 RestoreUndoSerialNumber ();
4401 if (!TEST_FLAGS (flags
, pad
))
4403 if (pad
->Clearance
< value
)
4405 ChangeObjectClearSize (PAD_TYPE
, element
, pad
, 0,
4407 RestoreUndoSerialNumber ();
4413 VIA_LOOP (PCB
->Data
);
4415 if (!TEST_FLAGS (flags
, via
))
4417 if (via
->Clearance
< value
)
4419 ChangeObjectClearSize (VIA_TYPE
, via
, 0, 0, value
, 1);
4420 RestoreUndoSerialNumber ();
4424 ALLLINE_LOOP (PCB
->Data
);
4426 if (!TEST_FLAGS (flags
, line
))
4428 if (line
->Clearance
< value
)
4430 ChangeObjectClearSize (LINE_TYPE
, layer
, line
, 0, value
, 1);
4431 RestoreUndoSerialNumber ();
4435 ALLARC_LOOP (PCB
->Data
);
4437 if (!TEST_FLAGS (flags
, arc
))
4439 if (arc
->Clearance
< value
)
4441 ChangeObjectClearSize (ARC_TYPE
, layer
, arc
, 0, value
, 1);
4442 RestoreUndoSerialNumber ();
4446 RestoreUndoSerialNumber ();
4447 IncrementUndoSerialNumber ();
4451 /* --------------------------------------------------------------------------- */
4453 static const char changepinname_syntax
[] =
4454 "ChangePinName(ElementName,PinNumber,PinName)";
4456 static const char changepinname_help
[] =
4457 "Sets the name of a specific pin on a specific element.";
4459 /* %start-doc actions ChangePinName
4461 This can be especially useful for annotating pin names from a
4462 schematic to the layout without requiring knowledge of the pcb file
4466 ChangePinName(U3, 7, VCC)
4472 ActionChangePinName (int argc
, char **argv
, Coord x
, Coord y
)
4475 char *refdes
, *pinnum
, *pinname
;
4479 AFAIL (changepinname
);
4486 ELEMENT_LOOP (PCB
->Data
);
4488 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
4492 if (NSTRCMP (pinnum
, pin
->Number
) == 0)
4494 AddObjectToChangeNameUndoList (PIN_TYPE
, NULL
, NULL
,
4497 * Note: we can't free() pin->Name first because
4498 * it is used in the undo list
4500 pin
->Name
= strdup (pinname
);
4501 SetChangedFlag (true);
4509 if (NSTRCMP (pinnum
, pad
->Number
) == 0)
4511 AddObjectToChangeNameUndoList (PAD_TYPE
, NULL
, NULL
,
4514 * Note: we can't free() pad->Name first because
4515 * it is used in the undo list
4517 pad
->Name
= strdup (pinname
);
4518 SetChangedFlag (true);
4527 * done with our action so increment the undo # if we actually
4533 defer_needs_update
= 1;
4536 IncrementUndoSerialNumber ();
4537 gui
->invalidate_all ();
4544 /* --------------------------------------------------------------------------- */
4546 static const char changename_syntax
[] =
4547 "ChangeName(Object)\n"
4548 "ChangeName(Layout|Layer)";
4550 static const char changename_help
[] = "Sets the name of objects.";
4552 /* %start-doc actions ChangeName
4557 Changes the name of the element under the cursor.
4560 Changes the name of the layout. This is printed on the fab drawings.
4563 Changes the name of the currently active layer.
4570 ActionChangeName (int argc
, char **argv
, Coord x
, Coord y
)
4572 char *function
= ARG (0);
4577 switch (GetFunctionID (function
))
4579 /* change the name of an object */
4583 void *ptr1
, *ptr2
, *ptr3
;
4585 gui
->get_coords (_("Select an Object"), &x
, &y
);
4587 SearchScreen (x
, y
, CHANGENAME_TYPES
,
4588 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4590 SaveUndoSerialNumber ();
4591 if (QueryInputAndChangeObjectName (type
, ptr1
, ptr2
, ptr3
))
4593 SetChangedFlag (true);
4594 if (type
== ELEMENT_TYPE
)
4596 RubberbandType
*ptr
;
4599 RestoreUndoSerialNumber ();
4600 Crosshair
.AttachedObject
.RubberbandN
= 0;
4601 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
4602 ptr
= Crosshair
.AttachedObject
.Rubberband
;
4603 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
;
4607 EraseRat ((RatType
*) ptr
->Line
);
4608 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
4609 ptr
->Line
, ptr
->Line
,
4612 IncrementUndoSerialNumber ();
4620 /* change the layout's name */
4623 gui
->prompt_for (_("Enter the layout name:"), EMPTY (PCB
->Name
));
4624 /* NB: ChangeLayoutName takes ownership of the passed memory */
4625 if (name
&& ChangeLayoutName (name
))
4626 SetChangedFlag (true);
4629 /* change the name of the active layer */
4631 name
= gui
->prompt_for (_("Enter the layer name:"),
4632 EMPTY (CURRENT
->Name
));
4633 /* NB: ChangeLayerName takes ownership of the passed memory */
4634 if (name
&& ChangeLayerName (CURRENT
, name
))
4635 SetChangedFlag (true);
4643 /* --------------------------------------------------------------------------- */
4645 static const char morphpolygon_syntax
[] = "MorphPolygon(Object|Selected)";
4647 static const char morphpolygon_help
[] =
4648 "Converts dead polygon islands into separate polygons.";
4650 /* %start-doc actions MorphPolygon
4652 If a polygon is divided into unconnected "islands", you can use
4653 this command to convert the otherwise disappeared islands into
4654 separate polygons. Be sure the cursor is over a portion of the
4655 polygon that remains visible. Very small islands that may flake
4656 off are automatically deleted.
4661 ActionMorphPolygon (int argc
, char **argv
, Coord x
, Coord y
)
4663 char *function
= ARG (0);
4666 switch (GetFunctionID (function
))
4671 void *ptr1
, *ptr2
, *ptr3
;
4673 gui
->get_coords (_("Select an Object"), &x
, &y
);
4674 if ((type
= SearchScreen (x
, y
, POLYGON_TYPE
,
4675 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4677 MorphPolygon ((LayerType
*) ptr1
, (PolygonType
*) ptr3
);
4679 IncrementUndoSerialNumber ();
4684 case F_SelectedObjects
:
4685 ALLPOLYGON_LOOP (PCB
->Data
);
4687 if (TEST_FLAG (SELECTEDFLAG
, polygon
))
4688 MorphPolygon (layer
, polygon
);
4692 IncrementUndoSerialNumber ();
4699 /* --------------------------------------------------------------------------- */
4701 static const char togglehidename_syntax
[] =
4702 "ToggleHideName(Object|SelectedElements)";
4704 static const char togglehidename_help
[] =
4705 "Toggles the visibility of element names.";
4707 /* %start-doc actions ToggleHideName
4709 If names are hidden you won't see them on the screen and they will not
4710 appear on the silk layer when you print the layout.
4715 ActionToggleHideName (int argc
, char **argv
, Coord x
, Coord y
)
4717 char *function
= ARG (0);
4718 if (function
&& PCB
->ElementOn
)
4720 switch (GetFunctionID (function
))
4725 void *ptr1
, *ptr2
, *ptr3
;
4727 gui
->get_coords (_("Select an Object"), &x
, &y
);
4728 if ((type
= SearchScreen (x
, y
, ELEMENT_TYPE
,
4729 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4731 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr3
);
4732 EraseElementName ((ElementType
*) ptr2
);
4733 TOGGLE_FLAG (HIDENAMEFLAG
, (ElementType
*) ptr2
);
4734 DrawElementName ((ElementType
*) ptr2
);
4736 IncrementUndoSerialNumber ();
4740 case F_SelectedElements
:
4743 bool changed
= false;
4744 ELEMENT_LOOP (PCB
->Data
);
4746 if ((TEST_FLAG (SELECTEDFLAG
, element
) ||
4747 TEST_FLAG (SELECTEDFLAG
,
4748 &NAMEONPCB_TEXT (element
)))
4749 && (FRONT (element
) || PCB
->InvisibleObjectsOn
))
4751 AddObjectToFlagUndoList (ELEMENT_TYPE
, element
,
4753 EraseElementName (element
);
4754 TOGGLE_FLAG (HIDENAMEFLAG
, element
);
4755 DrawElementName (element
);
4763 IncrementUndoSerialNumber ();
4771 /* --------------------------------------------------------------------------- */
4773 static const char changejoin_syntax
[] =
4774 "ChangeJoin(ToggleObject|SelectedLines|SelectedArcs|Selected)";
4776 static const char changejoin_help
[] =
4777 "Changes the join (clearance through polygons) of objects.";
4779 /* %start-doc actions ChangeJoin
4781 The join flag determines whether a line or arc, drawn to intersect a
4782 polygon, electrically connects to the polygon or not. When joined,
4783 the line/arc is simply drawn over the polygon, making an electrical
4784 connection. When not joined, a gap is drawn between the line and the
4785 polygon, insulating them from each other.
4790 ActionChangeJoin (int argc
, char **argv
, Coord x
, Coord y
)
4792 char *function
= ARG (0);
4795 switch (GetFunctionID (function
))
4797 case F_ToggleObject
:
4801 void *ptr1
, *ptr2
, *ptr3
;
4803 gui
->get_coords (_("Select an Object"), &x
, &y
);
4805 SearchScreen (x
, y
, CHANGEJOIN_TYPES
,
4806 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4807 if (ChangeObjectJoin (type
, ptr1
, ptr2
, ptr3
))
4808 SetChangedFlag (true);
4812 case F_SelectedLines
:
4813 if (ChangeSelectedJoin (LINE_TYPE
))
4814 SetChangedFlag (true);
4817 case F_SelectedArcs
:
4818 if (ChangeSelectedJoin (ARC_TYPE
))
4819 SetChangedFlag (true);
4823 case F_SelectedObjects
:
4824 if (ChangeSelectedJoin (CHANGEJOIN_TYPES
))
4825 SetChangedFlag (true);
4832 /* --------------------------------------------------------------------------- */
4834 static const char changesquare_syntax
[] =
4835 "ChangeSquare(ToggleObject)\n"
4836 "ChangeSquare(SelectedElements|SelectedPins)\n"
4837 "ChangeSquare(Selected|SelectedObjects)";
4839 static const char changesquare_help
[] =
4840 "Changes the square flag of pins and pads.";
4842 /* %start-doc actions ChangeSquare
4844 Note that @code{Pins} means both pins and pads.
4851 ActionChangeSquare (int argc
, char **argv
, Coord x
, Coord y
)
4853 char *function
= ARG (0);
4856 switch (GetFunctionID (function
))
4858 case F_ToggleObject
:
4862 void *ptr1
, *ptr2
, *ptr3
;
4864 gui
->get_coords (_("Select an Object"), &x
, &y
);
4866 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4867 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4868 if (ChangeObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4869 SetChangedFlag (true);
4873 case F_SelectedElements
:
4874 if (ChangeSelectedSquare (ELEMENT_TYPE
))
4875 SetChangedFlag (true);
4878 case F_SelectedPins
:
4879 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4880 SetChangedFlag (true);
4884 case F_SelectedObjects
:
4885 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4886 SetChangedFlag (true);
4893 /* --------------------------------------------------------------------------- */
4895 static const char setsquare_syntax
[] =
4896 "SetSquare(ToggleObject|SelectedElements|SelectedPins)";
4898 static const char setsquare_help
[] = "sets the square-flag of objects.";
4900 /* %start-doc actions SetSquare
4902 Note that @code{Pins} means pins and pads.
4909 ActionSetSquare (int argc
, char **argv
, Coord x
, Coord y
)
4911 char *function
= ARG (0);
4912 if (function
&& *function
)
4914 switch (GetFunctionID (function
))
4916 case F_ToggleObject
:
4920 void *ptr1
, *ptr2
, *ptr3
;
4922 gui
->get_coords (_("Select an Object"), &x
, &y
);
4924 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4925 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4926 if (SetObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4927 SetChangedFlag (true);
4931 case F_SelectedElements
:
4932 if (SetSelectedSquare (ELEMENT_TYPE
))
4933 SetChangedFlag (true);
4936 case F_SelectedPins
:
4937 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4938 SetChangedFlag (true);
4942 case F_SelectedObjects
:
4943 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4944 SetChangedFlag (true);
4951 /* --------------------------------------------------------------------------- */
4953 static const char clearsquare_syntax
[] =
4954 "ClearSquare(ToggleObject|SelectedElements|SelectedPins)";
4956 static const char clearsquare_help
[] =
4957 "Clears the square-flag of pins and pads.";
4959 /* %start-doc actions ClearSquare
4961 Note that @code{Pins} means pins and pads.
4968 ActionClearSquare (int argc
, char **argv
, Coord x
, Coord y
)
4970 char *function
= ARG (0);
4971 if (function
&& *function
)
4973 switch (GetFunctionID (function
))
4975 case F_ToggleObject
:
4979 void *ptr1
, *ptr2
, *ptr3
;
4981 gui
->get_coords (_("Select an Object"), &x
, &y
);
4983 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4984 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4985 if (ClrObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4986 SetChangedFlag (true);
4990 case F_SelectedElements
:
4991 if (ClrSelectedSquare (ELEMENT_TYPE
))
4992 SetChangedFlag (true);
4995 case F_SelectedPins
:
4996 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4997 SetChangedFlag (true);
5001 case F_SelectedObjects
:
5002 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
5003 SetChangedFlag (true);
5010 /* --------------------------------------------------------------------------- */
5012 static const char changeoctagon_syntax
[] =
5013 "ChangeOctagon(Object|ToggleObject|SelectedObjects|Selected)\n"
5014 "ChangeOctagon(SelectedElements|SelectedPins|SelectedVias)";
5016 static const char changeoctagon_help
[] =
5017 "Changes the octagon-flag of pins and vias.";
5019 /* %start-doc actions ChangeOctagon
5026 ActionChangeOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5028 char *function
= ARG (0);
5031 switch (GetFunctionID (function
))
5033 case F_ToggleObject
:
5037 void *ptr1
, *ptr2
, *ptr3
;
5039 gui
->get_coords (_("Select an Object"), &x
, &y
);
5041 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5042 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5043 if (ChangeObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5044 SetChangedFlag (true);
5048 case F_SelectedElements
:
5049 if (ChangeSelectedOctagon (ELEMENT_TYPE
))
5050 SetChangedFlag (true);
5053 case F_SelectedPins
:
5054 if (ChangeSelectedOctagon (PIN_TYPE
))
5055 SetChangedFlag (true);
5058 case F_SelectedVias
:
5059 if (ChangeSelectedOctagon (VIA_TYPE
))
5060 SetChangedFlag (true);
5064 case F_SelectedObjects
:
5065 if (ChangeSelectedOctagon (PIN_TYPES
))
5066 SetChangedFlag (true);
5073 /* --------------------------------------------------------------------------- */
5075 static const char setoctagon_syntax
[] =
5076 "SetOctagon(Object|ToggleObject|SelectedElements|Selected)";
5078 static const char setoctagon_help
[] = "Sets the octagon-flag of objects.";
5080 /* %start-doc actions SetOctagon
5087 ActionSetOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5089 char *function
= ARG (0);
5092 switch (GetFunctionID (function
))
5094 case F_ToggleObject
:
5098 void *ptr1
, *ptr2
, *ptr3
;
5100 gui
->get_coords (_("Select an Object"), &x
, &y
);
5102 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5103 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5104 if (SetObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5105 SetChangedFlag (true);
5109 case F_SelectedElements
:
5110 if (SetSelectedOctagon (ELEMENT_TYPE
))
5111 SetChangedFlag (true);
5114 case F_SelectedPins
:
5115 if (SetSelectedOctagon (PIN_TYPE
))
5116 SetChangedFlag (true);
5119 case F_SelectedVias
:
5120 if (SetSelectedOctagon (VIA_TYPE
))
5121 SetChangedFlag (true);
5125 case F_SelectedObjects
:
5126 if (SetSelectedOctagon (PIN_TYPES
))
5127 SetChangedFlag (true);
5134 /* --------------------------------------------------------------------------- */
5136 static const char clearoctagon_syntax
[] =
5137 "ClearOctagon(ToggleObject|Object|SelectedObjects|Selected)\n"
5138 "ClearOctagon(SelectedElements|SelectedPins|SelectedVias)";
5140 static const char clearoctagon_help
[] =
5141 "Clears the octagon-flag of pins and vias.";
5143 /* %start-doc actions ClearOctagon
5150 ActionClearOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5152 char *function
= ARG (0);
5155 switch (GetFunctionID (function
))
5157 case F_ToggleObject
:
5161 void *ptr1
, *ptr2
, *ptr3
;
5163 gui
->get_coords (_("Select an Object"), &x
, &y
);
5165 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGEOCTAGON_TYPES
,
5166 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5167 if (ClrObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5168 SetChangedFlag (true);
5172 case F_SelectedElements
:
5173 if (ClrSelectedOctagon (ELEMENT_TYPE
))
5174 SetChangedFlag (true);
5177 case F_SelectedPins
:
5178 if (ClrSelectedOctagon (PIN_TYPE
))
5179 SetChangedFlag (true);
5182 case F_SelectedVias
:
5183 if (ClrSelectedOctagon (VIA_TYPE
))
5184 SetChangedFlag (true);
5188 case F_SelectedObjects
:
5189 if (ClrSelectedOctagon (PIN_TYPES
))
5190 SetChangedFlag (true);
5197 /* --------------------------------------------------------------------------- */
5199 static const char changehold_syntax
[] =
5200 "ChangeHole(ToggleObject|Object|SelectedVias|Selected)";
5202 static const char changehold_help
[] = "Changes the hole flag of objects.";
5204 /* %start-doc actions ChangeHole
5206 The "hole flag" of a via determines whether the via is a
5207 plated-through hole (not set), or an unplated hole (set).
5212 ActionChangeHole (int argc
, char **argv
, Coord x
, Coord y
)
5214 char *function
= ARG (0);
5217 switch (GetFunctionID (function
))
5219 case F_ToggleObject
:
5223 void *ptr1
, *ptr2
, *ptr3
;
5225 gui
->get_coords (_("Select an Object"), &x
, &y
);
5226 if ((type
= SearchScreen (x
, y
, VIA_TYPE
,
5227 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5228 && ChangeHole ((PinType
*) ptr3
))
5229 IncrementUndoSerialNumber ();
5233 case F_SelectedVias
:
5235 if (ChangeSelectedHole ())
5236 SetChangedFlag (true);
5243 /* --------------------------------------------------------------------------- */
5245 static const char changepaste_syntax
[] =
5246 "ChangePaste(ToggleObject|Object|SelectedPads|Selected)";
5248 static const char changepaste_help
[] = "Changes the no paste flag of objects.";
5250 /* %start-doc actions ChangePaste
5252 The "no paste flag" of a pad determines whether the solderpaste
5253 stencil will have an opening for the pad (no set) or if there wil be
5254 no solderpaste on the pad (set). This is used for things such as
5260 ActionChangePaste (int argc
, char **argv
, Coord x
, Coord y
)
5262 char *function
= ARG (0);
5265 switch (GetFunctionID (function
))
5267 case F_ToggleObject
:
5271 void *ptr1
, *ptr2
, *ptr3
;
5273 gui
->get_coords (_("Select an Object"), &x
, &y
);
5274 if ((type
= SearchScreen (x
, y
, PAD_TYPE
,
5275 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5276 && ChangePaste ((PadType
*) ptr3
))
5277 IncrementUndoSerialNumber ();
5281 case F_SelectedPads
:
5283 if (ChangeSelectedPaste ())
5284 SetChangedFlag (true);
5291 /* --------------------------------------------------------------------------- */
5293 static const char select_syntax
[] =
5294 "Select(Object|ToggleObject)\n"
5295 "Select(All|Block|Connection)\n"
5296 "Select(ElementByName|ObjectByName|PadByName|PinByName)\n"
5297 "Select(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5298 "Select(TextByName|ViaByName|NetByName)\n"
5299 "Select(TextByName|ViaByName|NetByName, Name)\n"
5302 static const char select_help
[] = "Toggles or sets the selection.";
5304 /* %start-doc actions Select
5316 These all rely on having a regular expression parser built into
5317 @code{pcb}. If the name is not specified then the user is prompted
5318 for a pattern, and all objects that match the pattern and are of the
5319 type specified are selected.
5323 Selects the object under the cursor.
5326 Selects all objects in a rectangle indicated by the cursor.
5329 Selects all objects on the board.
5332 Selects all connections with the ``found'' flag set.
5335 Selects all connections with the ``connected'' flag set.
5338 Converts the selected objects to an element. This uses the highest
5339 numbered paste buffer.
5346 ActionSelect (int argc
, char **argv
, Coord x
, Coord y
)
5348 char *function
= ARG (0);
5351 switch (GetFunctionID (function
))
5353 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5355 /* select objects by their names */
5356 case F_ElementByName
:
5357 type
= ELEMENT_TYPE
;
5359 case F_ObjectByName
:
5380 char *pattern
= ARG (1);
5384 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5386 if (SelectObjectByName (type
, pattern
, true))
5387 SetChangedFlag (true);
5388 if (ARG (1) == NULL
)
5393 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5395 /* select a single object */
5396 case F_ToggleObject
:
5398 if (SelectObject ())
5399 SetChangedFlag (true);
5402 /* all objects in block */
5407 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5408 Crosshair
.AttachedBox
.Point2
.X
);
5409 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5410 Crosshair
.AttachedBox
.Point2
.Y
);
5411 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5412 Crosshair
.AttachedBox
.Point2
.X
);
5413 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5414 Crosshair
.AttachedBox
.Point2
.Y
);
5415 notify_crosshair_change (false);
5417 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5418 SelectBlock (&box
, true))
5420 SetChangedFlag (true);
5421 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5423 notify_crosshair_change (true);
5427 /* select all visible objects */
5432 box
.X1
= -MAX_COORD
;
5433 box
.Y1
= -MAX_COORD
;
5436 if (SelectBlock (&box
, true))
5437 SetChangedFlag (true);
5441 /* all logical connections */
5443 if (SelectByFlag (FOUNDFLAG
, true))
5446 IncrementUndoSerialNumber ();
5447 SetChangedFlag (true);
5451 /* all physical connections */
5453 if (SelectByFlag (CONNECTEDFLAG
, true))
5456 IncrementUndoSerialNumber ();
5457 SetChangedFlag (true);
5464 Note
.Buffer
= Settings
.BufferNumber
;
5465 SetBufferNumber (MAX_BUFFER
- 1);
5466 ClearBuffer (PASTEBUFFER
);
5467 gui
->get_coords (_("Select the Element's Mark Location"), &x
, &y
);
5468 x
= GridFit (x
, PCB
->Grid
, PCB
->GridOffsetX
);
5469 y
= GridFit (y
, PCB
->Grid
, PCB
->GridOffsetY
);
5470 AddSelectedToBuffer (PASTEBUFFER
, x
, y
, true);
5471 SaveUndoSerialNumber ();
5473 ConvertBufferToElement (PASTEBUFFER
);
5474 RestoreUndoSerialNumber ();
5475 CopyPastebufferToLayout (x
, y
);
5476 SetBufferNumber (Note
.Buffer
);
5488 /* FLAG(have_regex,FlagHaveRegex,0) */
5490 FlagHaveRegex (int parm
)
5492 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5499 /* --------------------------------------------------------------------------- */
5501 static const char unselect_syntax
[] =
5502 "Unselect(All|Block|Connection)\n"
5503 "Unselect(ElementByName|ObjectByName|PadByName|PinByName)\n"
5504 "Unselect(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5505 "Unselect(TextByName|ViaByName)\n"
5506 "Unselect(TextByName|ViaByName, Name)\n";
5508 static const char unselect_help
[] =
5509 "Unselects the object at the pointer location or the specified objects.";
5511 /* %start-doc actions Unselect
5516 Unselect all objects.
5519 Unselect all objects in a rectangle given by the cursor.
5522 Unselect all connections with the ``found'' flag set.
5531 These all rely on having a regular expression parser built into
5532 @code{pcb}. If the name is not specified then the user is prompted
5533 for a pattern, and all objects that match the pattern and are of the
5534 type specified are unselected.
5542 ActionUnselect (int argc
, char **argv
, Coord x
, Coord y
)
5544 char *function
= ARG (0);
5547 switch (GetFunctionID (function
))
5549 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5551 /* select objects by their names */
5552 case F_ElementByName
:
5553 type
= ELEMENT_TYPE
;
5555 case F_ObjectByName
:
5576 char *pattern
= ARG (1);
5580 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5582 if (SelectObjectByName (type
, pattern
, false))
5583 SetChangedFlag (true);
5584 if (ARG (1) == NULL
)
5589 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5591 /* all objects in block */
5596 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5597 Crosshair
.AttachedBox
.Point2
.X
);
5598 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5599 Crosshair
.AttachedBox
.Point2
.Y
);
5600 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5601 Crosshair
.AttachedBox
.Point2
.X
);
5602 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5603 Crosshair
.AttachedBox
.Point2
.Y
);
5604 notify_crosshair_change (false);
5606 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5607 SelectBlock (&box
, false))
5609 SetChangedFlag (true);
5610 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5612 notify_crosshair_change (true);
5616 /* unselect all visible objects */
5621 box
.X1
= -MAX_COORD
;
5622 box
.Y1
= -MAX_COORD
;
5625 if (SelectBlock (&box
, false))
5626 SetChangedFlag (true);
5630 /* all logical connections */
5632 if (SelectByFlag (FOUNDFLAG
, false))
5635 IncrementUndoSerialNumber ();
5636 SetChangedFlag (true);
5640 /* all physical connections */
5642 if (SelectByFlag (CONNECTEDFLAG
, false))
5645 IncrementUndoSerialNumber ();
5646 SetChangedFlag (true);
5659 /* --------------------------------------------------------------------------- */
5661 static const char saveto_syntax
[] =
5662 "SaveTo(Layout|LayoutAs,filename)\n"
5663 "SaveTo(AllConnections|AllUnusedPins|ElementConnections,filename)\n"
5664 "SaveTo(PasteBuffer,filename)";
5666 static const char saveto_help
[] = "Saves data to a file.";
5668 /* %start-doc actions SaveTo
5673 Saves the current layout.
5676 Saves the current layout, and remembers the filename used.
5678 @item AllConnections
5679 Save all connections to a file.
5682 List all unused pins to a file.
5684 @item ElementConnections
5685 Save connections to the element at the cursor to a file.
5688 Save the content of the active Buffer to a file. This is the graphical way to create a footprint.
5695 ActionSaveTo (int argc
, char **argv
, Coord x
, Coord y
)
5703 if (strcasecmp (function
, "Layout") == 0)
5705 if (SavePCB (PCB
->Filename
) == 0)
5706 SetChangedFlag (false);
5713 if (strcasecmp (function
, "LayoutAs") == 0)
5715 if (SavePCB (name
) == 0)
5717 SetChangedFlag (false);
5718 free (PCB
->Filename
);
5719 PCB
->Filename
= strdup (name
);
5720 if (gui
->notify_filename_changed
!= NULL
)
5721 gui
->notify_filename_changed ();
5726 if (strcasecmp (function
, "AllConnections") == 0)
5730 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5732 LookupConnectionsToAllElements (fp
);
5734 SetChangedFlag (true);
5739 if (strcasecmp (function
, "AllUnusedPins") == 0)
5743 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5745 LookupUnusedPins (fp
);
5747 SetChangedFlag (true);
5752 if (strcasecmp (function
, "ElementConnections") == 0)
5754 ElementType
*element
;
5759 if ((SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
5760 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
5762 element
= (ElementType
*) ptrtmp
;
5764 CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5766 LookupElementConnections (element
, fp
);
5768 SetChangedFlag (true);
5774 if (strcasecmp (function
, "PasteBuffer") == 0)
5776 return SaveBufferElements (name
);
5782 /* --------------------------------------------------------------------------- */
5784 static const char savesettings_syntax
[] =
5786 "SaveSettings(local)";
5788 static const char savesettings_help
[] = "Saves settings.";
5790 /* %start-doc actions SaveSettings
5792 If you pass no arguments, the settings are stored in
5793 @code{$HOME/.pcb/settings}. If you pass the word @code{local} they're
5794 saved in @code{./pcb.settings}.
5799 ActionSaveSettings (int argc
, char **argv
, Coord x
, Coord y
)
5801 int locally
= argc
> 0 ? (strncasecmp (argv
[0], "local", 5) == 0) : 0;
5802 hid_save_settings (locally
);
5806 /* --------------------------------------------------------------------------- */
5808 static const char loadfrom_syntax
[] =
5809 "LoadFrom(Layout|LayoutToBuffer|ElementToBuffer|Netlist|Revert,filename)";
5811 static const char loadfrom_help
[] = "Load layout data from a file.";
5813 /* %start-doc actions LoadFrom
5815 This action assumes you know what the filename is. The various GUIs
5816 should have a similar @code{Load} action where the filename is
5817 optional, and will provide their own file selection mechanism to let
5818 you choose the file name.
5823 Loads an entire PCB layout, replacing the current one.
5825 @item LayoutToBuffer
5826 Loads an entire PCB layout to the paste buffer.
5828 @item ElementToBuffer
5829 Loads the given element file into the paste buffer. Element files
5830 contain only a single @code{Element} definition, such as the
5831 ``newlib'' library uses.
5834 Loads a new netlist, replacing any current netlist.
5837 Re-loads the current layout from its disk file, reverting any changes
5845 ActionLoadFrom (int argc
, char **argv
, Coord x
, Coord y
)
5856 if (strcasecmp (function
, "ElementToBuffer") == 0)
5858 notify_crosshair_change (false);
5859 if (LoadElementToBuffer (PASTEBUFFER
, name
, true))
5860 SetMode (PASTEBUFFER_MODE
);
5861 notify_crosshair_change (true);
5864 else if (strcasecmp (function
, "LayoutToBuffer") == 0)
5866 notify_crosshair_change (false);
5867 if (LoadLayoutToBuffer (PASTEBUFFER
, name
))
5868 SetMode (PASTEBUFFER_MODE
);
5869 notify_crosshair_change (true);
5872 else if (strcasecmp (function
, "Layout") == 0)
5874 if (!PCB
->Changed
||
5875 gui
->confirm_dialog (_("OK to override layout data?"), 0))
5879 else if (strcasecmp (function
, "Netlist") == 0)
5881 if (PCB
->Netlistname
)
5882 free (PCB
->Netlistname
);
5883 PCB
->Netlistname
= StripWhiteSpaceAndDup (name
);
5884 FreeLibraryMemory (&PCB
->NetlistLib
);
5885 ImportNetlist (PCB
->Netlistname
);
5888 else if (strcasecmp (function
, "Revert") == 0 && PCB
->Filename
5890 || gui
->confirm_dialog (_("OK to override changes?"), 0)))
5898 /* --------------------------------------------------------------------------- */
5900 static const char new_syntax
[] = "New([name])";
5902 static const char new_help
[] = "Starts a new layout.";
5904 /* %start-doc actions New
5906 If a name is not given, one is prompted for.
5911 ActionNew (int argc
, char **argv
, Coord x
, Coord y
)
5913 char *name
= ARG (0);
5915 if (!PCB
->Changed
|| gui
->confirm_dialog (_("OK to clear layout data?"), 0))
5918 name
= strdup (name
);
5920 name
= gui
->prompt_for (_("Enter the layout name:"), "");
5925 notify_crosshair_change (false);
5926 /* do emergency saving
5927 * clear the old struct and allocate memory for the new one
5929 if (PCB
->Changed
&& Settings
.SaveInTMP
)
5933 PCB
= CreateNewPCB (true);
5934 PCB
->Data
->LayerN
= DEF_LAYER
;
5935 CreateNewPCBPost (PCB
, 1);
5937 /* setup the new name and reset some values to default */
5941 ResetStackAndVisibility ();
5942 SetCrosshairRange (0, 0, PCB
->MaxWidth
, PCB
->MaxHeight
);
5943 CenterDisplay (PCB
->MaxWidth
/ 2, PCB
->MaxHeight
/ 2);
5946 hid_action ("PCBChanged");
5947 notify_crosshair_change (true);
5953 /* ---------------------------------------------------------------------------
5954 * no operation, just for testing purposes
5955 * syntax: Bell(volume)
5958 ActionBell (char *volume
)
5963 /* --------------------------------------------------------------------------- */
5965 static const char pastebuffer_syntax
[] =
5966 "PasteBuffer(AddSelected|Clear|1..MAX_BUFFER)\n"
5967 "PasteBuffer(Rotate, 1..3)\n"
5968 "PasteBuffer(Convert|Save|Restore|Mirror)\n"
5969 "PasteBuffer(ToLayout, X, Y, units)";
5971 static const char pastebuffer_help
[] =
5972 "Various operations on the paste buffer.";
5974 /* %start-doc actions PasteBuffer
5976 There are a number of paste buffers; the actual limit is a
5977 compile-time constant @code{MAX_BUFFER} in @file{globalconst.h}. It
5978 is currently @code{5}. One of these is the ``current'' paste buffer,
5979 often referred to as ``the'' paste buffer.
5984 Copies the selected objects to the current paste buffer.
5987 Remove all objects from the current paste buffer.
5990 Convert the current paste buffer to an element. Vias are converted to
5991 pins, lines are converted to pads.
5994 Convert any elements in the paste buffer back to vias and lines.
5997 Flip all objects in the paste buffer vertically (up/down flip). To mirror
5998 horizontally, combine this with rotations.
6001 Rotates the current buffer. The number to pass is 1..3, where 1 means
6002 90 degrees counter clockwise, 2 means 180 degrees, and 3 means 90
6003 degrees clockwise (270 CCW).
6006 Saves any elements in the current buffer to the indicated file.
6009 Pastes any elements in the current buffer to the indicated X, Y
6010 coordinates in the layout. The @code{X} and @code{Y} are treated like
6011 @code{delta} is for many other objects. For each, if it's prefixed by
6012 @code{+} or @code{-}, then that amount is relative to the last
6013 location. Otherwise, it's absolute. Units can be
6014 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
6015 units, currently 1/100 mil.
6019 Selects the given buffer to be the current paste buffer.
6026 ActionPasteBuffer (int argc
, char **argv
, Coord x
, Coord y
)
6028 char *function
= argc
? argv
[0] : (char *)"";
6029 char *sbufnum
= argc
> 1 ? argv
[1] : (char *)"";
6031 static char *default_file
= NULL
;
6034 notify_crosshair_change (false);
6037 switch (GetFunctionID (function
))
6039 /* clear contents of paste buffer */
6041 ClearBuffer (PASTEBUFFER
);
6044 /* copies objects to paste buffer */
6046 AddSelectedToBuffer (PASTEBUFFER
, 0, 0, false);
6049 /* converts buffer contents into an element */
6051 ConvertBufferToElement (PASTEBUFFER
);
6054 /* break up element for editing */
6056 SmashBufferElement (PASTEBUFFER
);
6061 MirrorBuffer (PASTEBUFFER
);
6067 RotateBuffer (PASTEBUFFER
, (BYTE
) atoi (sbufnum
));
6068 SetCrosshairRangeToBuffer ();
6073 if (PASTEBUFFER
->Data
->ElementN
== 0)
6075 Message (_("Buffer has no elements!\n"));
6081 name
= gui
->fileselect (_("Save Paste Buffer As ..."),
6082 _("Choose a file to save the contents of the\n"
6083 "paste buffer to.\n"),
6084 default_file
, ".fp", "footprint",
6089 free (default_file
);
6090 default_file
= NULL
;
6094 default_file
= strdup (name
);
6105 if ((exist
= fopen (name
, "r")))
6109 confirm_dialog (_("File exists! Ok to overwrite?"), 0))
6110 SaveBufferElements (name
);
6113 SaveBufferElements (name
);
6115 if (free_name
&& name
)
6122 static Coord oldx
= 0, oldy
= 0;
6130 else if (argc
== 3 || argc
== 4)
6132 x
= GetValue (ARG (1), ARG (3), &absolute
);
6135 y
= GetValue (ARG (2), ARG (3), &absolute
);
6141 notify_crosshair_change (true);
6142 AFAIL (pastebuffer
);
6147 if (CopyPastebufferToLayout (x
, y
))
6148 SetChangedFlag (true);
6155 int number
= atoi (function
);
6157 /* correct number */
6159 SetBufferNumber (number
- 1);
6164 notify_crosshair_change (true);
6168 /* --------------------------------------------------------------------------- */
6170 static const char undo_syntax
[] = "Undo()\n"
6173 static const char undo_help
[] = "Undo recent changes.";
6175 /* %start-doc actions Undo
6177 The unlimited undo feature of @code{Pcb} allows you to recover from
6178 most operations that materially affect you work. Calling
6179 @code{Undo()} without any parameter recovers from the last (non-undo)
6180 operation. @code{ClearList} is used to release the allocated
6181 memory. @code{ClearList} is called whenever a new layout is started or
6182 loaded. See also @code{Redo} and @code{Atomic}.
6184 Note that undo groups operations by serial number; changes with the
6185 same serial number will be undone (or redone) as a group. See
6191 ActionUndo (int argc
, char **argv
, Coord x
, Coord y
)
6193 char *function
= ARG (0);
6194 if (!function
|| !*function
)
6196 /* don't allow undo in the middle of an operation */
6197 if (Settings
.Mode
!= POLYGONHOLE_MODE
&&
6198 Crosshair
.AttachedObject
.State
!= STATE_FIRST
)
6200 if (Crosshair
.AttachedBox
.State
!= STATE_FIRST
6201 && Settings
.Mode
!= ARC_MODE
)
6203 /* undo the last operation */
6205 notify_crosshair_change (false);
6206 if ((Settings
.Mode
== POLYGON_MODE
||
6207 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6208 Crosshair
.AttachedPolygon
.PointN
)
6210 GoToPreviousPoint ();
6211 notify_crosshair_change (true);
6214 /* move anchor point if undoing during line creation */
6215 if (Settings
.Mode
== LINE_MODE
)
6217 if (Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6219 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6220 Undo (true); /* undo the connection find */
6221 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
6222 SetLocalRef (0, 0, false);
6223 notify_crosshair_change (true);
6226 if (Crosshair
.AttachedLine
.State
== STATE_THIRD
)
6229 void *ptr1
, *ptr3
, *ptrtmp
;
6231 /* this search is guaranteed to succeed */
6232 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6234 Crosshair
.AttachedLine
.Point1
.X
,
6235 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6236 ptr2
= (LineType
*) ptrtmp
;
6238 /* save both ends of line */
6239 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point1
.X
;
6240 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point1
.Y
;
6241 if ((type
= Undo (true)))
6242 SetChangedFlag (true);
6243 /* check that the undo was of the right type */
6244 if ((type
& UNDO_CREATE
) == 0)
6246 /* wrong undo type, restore anchor points */
6247 Crosshair
.AttachedLine
.Point2
.X
=
6248 Crosshair
.AttachedLine
.Point1
.X
;
6249 Crosshair
.AttachedLine
.Point2
.Y
=
6250 Crosshair
.AttachedLine
.Point1
.Y
;
6251 notify_crosshair_change (true);
6254 /* move to new anchor */
6255 Crosshair
.AttachedLine
.Point1
.X
=
6256 Crosshair
.AttachedLine
.Point2
.X
;
6257 Crosshair
.AttachedLine
.Point1
.Y
=
6258 Crosshair
.AttachedLine
.Point2
.Y
;
6259 /* check if an intermediate point was removed */
6260 if (type
& UNDO_REMOVE
)
6262 /* this search should find the restored line */
6263 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6266 Crosshair
.AttachedLine
.Point2
.X
,
6267 Crosshair
.AttachedLine
.Point2
.Y
, 0);
6268 ptr2
= (LineType
*) ptrtmp
;
6269 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6271 /* undo loses CONNECTEDFLAG and FOUNDFLAG */
6272 SET_FLAG(CONNECTEDFLAG
, ptr2
);
6273 SET_FLAG(FOUNDFLAG
, ptr2
);
6274 DrawLine (CURRENT
, ptr2
);
6276 Crosshair
.AttachedLine
.Point1
.X
=
6277 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point2
.X
;
6278 Crosshair
.AttachedLine
.Point1
.Y
=
6279 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point2
.Y
;
6281 FitCrosshairIntoGrid (Crosshair
.X
, Crosshair
.Y
);
6282 AdjustAttachedObjects ();
6283 if (--addedLines
== 0)
6285 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
6286 lastLayer
= CURRENT
;
6290 /* this search is guaranteed to succeed too */
6291 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6294 Crosshair
.AttachedLine
.Point1
.X
,
6295 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6296 ptr2
= (LineType
*) ptrtmp
;
6297 lastLayer
= (LayerType
*) ptr1
;
6299 notify_crosshair_change (true);
6303 if (Settings
.Mode
== ARC_MODE
)
6305 if (Crosshair
.AttachedBox
.State
== STATE_SECOND
)
6307 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
6308 notify_crosshair_change (true);
6311 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
)
6313 void *ptr1
, *ptr2
, *ptr3
;
6315 /* guaranteed to succeed */
6316 SearchObjectByLocation (ARC_TYPE
, &ptr1
, &ptr2
, &ptr3
,
6317 Crosshair
.AttachedBox
.Point1
.X
,
6318 Crosshair
.AttachedBox
.Point1
.Y
, 0);
6319 bx
= GetArcEnds ((ArcType
*) ptr2
);
6320 Crosshair
.AttachedBox
.Point1
.X
=
6321 Crosshair
.AttachedBox
.Point2
.X
= bx
->X1
;
6322 Crosshair
.AttachedBox
.Point1
.Y
=
6323 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y1
;
6324 AdjustAttachedObjects ();
6325 if (--addedLines
== 0)
6326 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
6329 /* undo the last destructive operation */
6331 SetChangedFlag (true);
6335 switch (GetFunctionID (function
))
6337 /* clear 'undo objects' list */
6339 ClearUndoList (false);
6343 notify_crosshair_change (true);
6347 /* --------------------------------------------------------------------------- */
6349 static const char redo_syntax
[] = "Redo()";
6351 static const char redo_help
[] = "Redo recent \"undo\" operations.";
6353 /* %start-doc actions Redo
6355 This routine allows you to recover from the last undo command. You
6356 might want to do this if you thought that undo was going to revert
6357 something other than what it actually did (in case you are confused
6358 about which operations are un-doable), or if you have been backing up
6359 through a long undo list and over-shoot your stopping point. Any
6360 change that is made since the undo in question will trim the redo
6361 list. For example if you add ten lines, then undo three of them you
6362 could use redo to put them back, but if you move a line on the board
6363 before performing the redo, you will lose the ability to "redo" the
6364 three "undone" lines.
6369 ActionRedo (int argc
, char **argv
, Coord x
, Coord y
)
6371 if (((Settings
.Mode
== POLYGON_MODE
||
6372 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6373 Crosshair
.AttachedPolygon
.PointN
) ||
6374 Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6376 notify_crosshair_change (false);
6379 SetChangedFlag (true);
6380 if (Settings
.Mode
== LINE_MODE
&&
6381 Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
6383 LineType
*line
= g_list_last (CURRENT
->Line
)->data
;
6384 Crosshair
.AttachedLine
.Point1
.X
=
6385 Crosshair
.AttachedLine
.Point2
.X
= line
->Point2
.X
;
6386 Crosshair
.AttachedLine
.Point1
.Y
=
6387 Crosshair
.AttachedLine
.Point2
.Y
= line
->Point2
.Y
;
6391 notify_crosshair_change (true);
6395 /* --------------------------------------------------------------------------- */
6397 static const char polygon_syntax
[] = "Polygon(Close|PreviousPoint)";
6399 static const char polygon_help
[] = "Some polygon related stuff.";
6401 /* %start-doc actions Polygon
6403 Polygons need a special action routine to make life easier.
6408 Creates the final segment of the polygon. This may fail if clipping
6409 to 45 degree lines is switched on, in which case a warning is issued.
6412 Resets the newly entered corner to the previous one. The Undo action
6413 will call Polygon(PreviousPoint) when appropriate to do so.
6420 ActionPolygon (int argc
, char **argv
, Coord x
, Coord y
)
6422 char *function
= ARG (0);
6423 if (function
&& Settings
.Mode
== POLYGON_MODE
)
6425 notify_crosshair_change (false);
6426 switch (GetFunctionID (function
))
6428 /* close open polygon if possible */
6433 /* go back to the previous point */
6434 case F_PreviousPoint
:
6435 GoToPreviousPoint ();
6438 notify_crosshair_change (true);
6443 /* --------------------------------------------------------------------------- */
6445 static const char routestyle_syntax
[] = "RouteStyle(1|2|3|4)";
6447 static const char routestyle_help
[] =
6448 "Copies the indicated routing style into the current sizes.";
6450 /* %start-doc actions RouteStyle
6455 ActionRouteStyle (int argc
, char **argv
, Coord x
, Coord y
)
6457 char *str
= ARG (0);
6458 RouteStyleType
*rts
;
6463 number
= atoi (str
);
6464 if (number
> 0 && number
<= NUM_STYLES
)
6466 rts
= &PCB
->RouteStyle
[number
- 1];
6467 SetLineSize (rts
->Thick
);
6468 SetViaSize (rts
->Diameter
, true);
6469 SetViaDrillingHole (rts
->Hole
, true);
6470 SetKeepawayWidth (rts
->Keepaway
);
6471 hid_action("RouteStylesChanged");
6478 /* --------------------------------------------------------------------------- */
6480 static const char moveobject_syntax
[] = "MoveObject(X,Y,dim)";
6482 static const char moveobject_help
[] = "Moves the object under the crosshair.";
6484 /* %start-doc actions MoveObject
6486 The @code{X} and @code{Y} are treated like @code{delta} is for many
6487 other objects. For each, if it's prefixed by @code{+} or @code{-},
6488 then that amount is relative. Otherwise, it's absolute. Units can be
6489 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
6490 units, currently 1/100 mil.
6495 ActionMoveObject (int argc
, char **argv
, Coord x
, Coord y
)
6497 char *x_str
= ARG (0);
6498 char *y_str
= ARG (1);
6499 char *units
= ARG (2);
6501 bool absolute1
, absolute2
;
6502 void *ptr1
, *ptr2
, *ptr3
;
6505 ny
= GetValue (y_str
, units
, &absolute1
);
6506 nx
= GetValue (x_str
, units
, &absolute2
);
6508 type
= SearchScreen (x
, y
, MOVE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6509 if (type
== NO_TYPE
)
6511 Message (_("Nothing found under crosshair\n"));
6518 Crosshair
.AttachedObject
.RubberbandN
= 0;
6519 if (TEST_FLAG (RUBBERBANDFLAG
, PCB
))
6520 LookupRubberbandLines (type
, ptr1
, ptr2
, ptr3
);
6521 if (type
== ELEMENT_TYPE
)
6522 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
6523 MoveObjectAndRubberband (type
, ptr1
, ptr2
, ptr3
, nx
, ny
);
6524 SetChangedFlag (true);
6528 /* --------------------------------------------------------------------------- */
6530 static const char movetocurrentlayer_syntax
[] =
6531 "MoveToCurrentLayer(Object|SelectedObjects)";
6533 static const char movetocurrentlayer_help
[] =
6534 "Moves objects to the current layer.";
6536 /* %start-doc actions MoveToCurrentLayer
6538 Note that moving an element from a component layer to a solder layer,
6539 or from solder to component, won't automatically flip it. Use the
6540 @code{Flip()} action to do that.
6545 ActionMoveToCurrentLayer (int argc
, char **argv
, Coord x
, Coord y
)
6547 char *function
= ARG (0);
6550 switch (GetFunctionID (function
))
6555 void *ptr1
, *ptr2
, *ptr3
;
6557 gui
->get_coords (_("Select an Object"), &x
, &y
);
6559 SearchScreen (x
, y
, MOVETOLAYER_TYPES
,
6560 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6561 if (MoveObjectToLayer (type
, ptr1
, ptr2
, ptr3
, CURRENT
, false))
6562 SetChangedFlag (true);
6566 case F_SelectedObjects
:
6568 if (MoveSelectedObjectsToLayer (CURRENT
))
6569 SetChangedFlag (true);
6577 static const char setsame_syntax
[] = "SetSame()";
6579 static const char setsame_help
[] =
6580 "Sets current layer and sizes to match indicated item.";
6582 /* %start-doc actions SetSame
6584 When invoked over any line, arc, polygon, or via, this changes the
6585 current layer to be the layer that item is on, and changes the current
6586 sizes (thickness, keepaway, drill, etc) according to that item.
6591 ActionSetSame (int argc
, char **argv
, Coord x
, Coord y
)
6593 void *ptr1
, *ptr2
, *ptr3
;
6595 LayerType
*layer
= CURRENT
;
6597 type
= SearchScreen (x
, y
, CLONE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6598 /* set layer current and size from line or arc */
6602 notify_crosshair_change (false);
6603 Settings
.LineThickness
= ((LineType
*) ptr2
)->Thickness
;
6604 Settings
.Keepaway
= ((LineType
*) ptr2
)->Clearance
/ 2;
6605 layer
= (LayerType
*) ptr1
;
6606 if (Settings
.Mode
!= LINE_MODE
)
6607 SetMode (LINE_MODE
);
6608 notify_crosshair_change (true);
6609 hid_action ("RouteStylesChanged");
6613 notify_crosshair_change (false);
6614 Settings
.LineThickness
= ((ArcType
*) ptr2
)->Thickness
;
6615 Settings
.Keepaway
= ((ArcType
*) ptr2
)->Clearance
/ 2;
6616 layer
= (LayerType
*) ptr1
;
6617 if (Settings
.Mode
!= ARC_MODE
)
6619 notify_crosshair_change (true);
6620 hid_action ("RouteStylesChanged");
6624 layer
= (LayerType
*) ptr1
;
6628 notify_crosshair_change (false);
6629 Settings
.ViaThickness
= ((PinType
*) ptr2
)->Thickness
;
6630 Settings
.ViaDrillingHole
= ((PinType
*) ptr2
)->DrillingHole
;
6631 Settings
.Keepaway
= ((PinType
*) ptr2
)->Clearance
/ 2;
6632 if (Settings
.Mode
!= VIA_MODE
)
6634 notify_crosshair_change (true);
6635 hid_action ("RouteStylesChanged");
6641 if (layer
!= CURRENT
)
6643 ChangeGroupVisibility (GetLayerNumber (PCB
->Data
, layer
), true, true);
6650 /* --------------------------------------------------------------------------- */
6652 static const char setflag_syntax
[] =
6653 "SetFlag(Object|Selected|SelectedObjects, flag)\n"
6654 "SetFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6655 "SetFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6656 "SetFlag(SelectedElements, flag)\n"
6657 "flag = square | octagon | thermal | join";
6659 static const char setflag_help
[] = "Sets flags on objects.";
6661 /* %start-doc actions SetFlag
6663 Turns the given flag on, regardless of its previous setting. See
6667 SetFlag(SelectedPins,thermal)
6673 ActionSetFlag (int argc
, char **argv
, Coord x
, Coord y
)
6675 char *function
= ARG (0);
6676 char *flag
= ARG (1);
6677 ChangeFlag (function
, flag
, 1, "SetFlag");
6681 /* --------------------------------------------------------------------------- */
6683 static const char clrflag_syntax
[] =
6684 "ClrFlag(Object|Selected|SelectedObjects, flag)\n"
6685 "ClrFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6686 "ClrFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6687 "ClrFlag(SelectedElements, flag)\n"
6688 "flag = square | octagon | thermal | join";
6690 static const char clrflag_help
[] = "Clears flags on objects.";
6692 /* %start-doc actions ClrFlag
6694 Turns the given flag off, regardless of its previous setting. See
6698 ClrFlag(SelectedLines,join)
6704 ActionClrFlag (int argc
, char **argv
, Coord x
, Coord y
)
6706 char *function
= ARG (0);
6707 char *flag
= ARG (1);
6708 ChangeFlag (function
, flag
, 0, "ClrFlag");
6712 /* --------------------------------------------------------------------------- */
6714 static const char changeflag_syntax
[] =
6715 "ChangeFlag(Object|Selected|SelectedObjects, flag, value)\n"
6716 "ChangeFlag(SelectedLines|SelectedPins|SelectedVias, flag, value)\n"
6717 "ChangeFlag(SelectedPads|SelectedTexts|SelectedNames, flag, value)\n"
6718 "ChangeFlag(SelectedElements, flag, value)\n"
6719 "flag = square | octagon | thermal | join\n"
6722 static const char changeflag_help
[] = "Sets or clears flags on objects.";
6724 /* %start-doc actions ChangeFlag
6726 Toggles the given flag on the indicated object(s). The flag may be
6727 one of the flags listed above (square, octagon, thermal, join). The
6728 value may be the number 0 or 1. If the value is 0, the flag is
6729 cleared. If the value is 1, the flag is set.
6734 ActionChangeFlag (int argc
, char **argv
, Coord x
, Coord y
)
6736 char *function
= ARG (0);
6737 char *flag
= ARG (1);
6738 int value
= argc
> 2 ? atoi (argv
[2]) : -1;
6739 if (value
!= 0 && value
!= 1)
6742 ChangeFlag (function
, flag
, value
, "ChangeFlag");
6748 ChangeFlag (char *what
, char *flag_name
, int value
, char *cmd_name
)
6750 bool (*set_object
) (int, void *, void *, void *);
6751 bool (*set_selected
) (int);
6753 if (NSTRCMP (flag_name
, "square") == 0)
6755 set_object
= value
? SetObjectSquare
: ClrObjectSquare
;
6756 set_selected
= value
? SetSelectedSquare
: ClrSelectedSquare
;
6758 else if (NSTRCMP (flag_name
, "octagon") == 0)
6760 set_object
= value
? SetObjectOctagon
: ClrObjectOctagon
;
6761 set_selected
= value
? SetSelectedOctagon
: ClrSelectedOctagon
;
6763 else if (NSTRCMP (flag_name
, "join") == 0)
6765 /* Note: these are backwards, because the flag is "clear" but
6766 the command is "join". */
6767 set_object
= value
? ClrObjectJoin
: SetObjectJoin
;
6768 set_selected
= value
? ClrSelectedJoin
: SetSelectedJoin
;
6772 Message (_("%s(): Flag \"%s\" is not valid\n"), cmd_name
, flag_name
);
6776 switch (GetFunctionID (what
))
6781 void *ptr1
, *ptr2
, *ptr3
;
6784 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
6785 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6786 if (TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
6787 Message (_("Sorry, the object is locked\n"));
6788 if (set_object (type
, ptr1
, ptr2
, ptr3
))
6789 SetChangedFlag (true);
6793 case F_SelectedVias
:
6794 if (set_selected (VIA_TYPE
))
6795 SetChangedFlag (true);
6798 case F_SelectedPins
:
6799 if (set_selected (PIN_TYPE
))
6800 SetChangedFlag (true);
6803 case F_SelectedPads
:
6804 if (set_selected (PAD_TYPE
))
6805 SetChangedFlag (true);
6808 case F_SelectedLines
:
6809 if (set_selected (LINE_TYPE
))
6810 SetChangedFlag (true);
6813 case F_SelectedTexts
:
6814 if (set_selected (TEXT_TYPE
))
6815 SetChangedFlag (true);
6818 case F_SelectedNames
:
6819 if (set_selected (ELEMENTNAME_TYPE
))
6820 SetChangedFlag (true);
6823 case F_SelectedElements
:
6824 if (set_selected (ELEMENT_TYPE
))
6825 SetChangedFlag (true);
6829 case F_SelectedObjects
:
6830 if (set_selected (CHANGESIZE_TYPES
))
6831 SetChangedFlag (true);
6836 /* --------------------------------------------------------------------------- */
6838 static const char executefile_syntax
[] = "ExecuteFile(filename)";
6840 static const char executefile_help
[] = "Run actions from the given file.";
6842 /* %start-doc actions ExecuteFile
6844 Lines starting with @code{#} are ignored.
6849 ActionExecuteFile (int argc
, char **argv
, Coord x
, Coord y
)
6858 AFAIL (executefile
);
6862 if ((fp
= fopen (fname
, "r")) == NULL
)
6864 fprintf (stderr
, _("Could not open actions file \"%s\".\n"), fname
);
6869 defer_needs_update
= 0;
6870 while (fgets (line
, sizeof (line
), fp
) != NULL
)
6875 /* eat the trailing newline */
6876 while (*sp
&& *sp
!= '\r' && *sp
!= '\n')
6880 /* eat leading spaces and tabs */
6882 while (*sp
&& (*sp
== ' ' || *sp
== '\t'))
6886 * if we have anything left and its not a comment line
6890 if (*sp
&& *sp
!= '#')
6892 /*Message ("%s : line %-3d : \"%s\"\n", fname, n, sp);*/
6893 hid_parse_actions (sp
);
6898 if (defer_needs_update
)
6900 IncrementUndoSerialNumber ();
6901 gui
->invalidate_all ();
6907 /* --------------------------------------------------------------------------- */
6910 ActionPSCalib (int argc
, char **argv
, Coord x
, Coord y
)
6912 HID
*ps
= hid_find_exporter ("ps");
6913 ps
->calibrate (0.0,0.0);
6917 /* --------------------------------------------------------------------------- */
6919 static ElementType
*element_cache
= NULL
;
6921 static ElementType
*
6922 find_element_by_refdes (char *refdes
)
6925 && NAMEONPCB_NAME(element_cache
)
6926 && strcmp (NAMEONPCB_NAME(element_cache
), refdes
) == 0)
6927 return element_cache
;
6929 ELEMENT_LOOP (PCB
->Data
);
6931 if (NAMEONPCB_NAME(element
)
6932 && strcmp (NAMEONPCB_NAME(element
), refdes
) == 0)
6934 element_cache
= element
;
6935 return element_cache
;
6942 static AttributeType
*
6943 lookup_attr (AttributeListType
*list
, const char *name
)
6946 for (i
=0; i
<list
->Number
; i
++)
6947 if (strcmp (list
->List
[i
].name
, name
) == 0)
6948 return & list
->List
[i
];
6953 delete_attr (AttributeListType
*list
, AttributeType
*attr
)
6955 int idx
= attr
- list
->List
;
6956 if (idx
< 0 || idx
>= list
->Number
)
6958 if (list
->Number
- idx
> 1)
6959 memmove (attr
, attr
+1, (list
->Number
- idx
- 1) * sizeof(AttributeType
));
6963 /* ---------------------------------------------------------------- */
6964 static const char elementlist_syntax
[] = "ElementList(Start|Done|Need,<refdes>,<footprint>,<value>)";
6966 static const char elementlist_help
[] = "Adds the given element if it doesn't already exist.";
6968 /* %start-doc actions elementlist
6973 Indicates the start of an element list; call this before any Need
6977 Searches the board for an element with a matching refdes.
6979 If found, the value and footprint are updated.
6981 If not found, a new element is created with the given footprint and value.
6984 Compares the list of elements needed since the most recent
6985 @code{start} with the list of elements actually on the board. Any
6986 elements that weren't listed are selected, so that the user may delete
6993 static int number_of_footprints_not_found
;
6996 parse_layout_attribute_units (char *name
, int def
)
6998 const char *as
= AttributeGet (PCB
, name
);
7001 return GetValue (as
, NULL
, NULL
);
7005 ActionElementList (int argc
, char **argv
, Coord x
, Coord y
)
7007 ElementType
*e
= NULL
;
7008 char *refdes
, *value
, *footprint
, *old
;
7010 char *function
= argv
[0];
7013 printf("Entered ActionElementList, executing function %s\n", function
);
7016 if (strcasecmp (function
, "start") == 0)
7018 ELEMENT_LOOP (PCB
->Data
);
7020 CLEAR_FLAG (FOUNDFLAG
, element
);
7023 element_cache
= NULL
;
7024 number_of_footprints_not_found
= 0;
7028 if (strcasecmp (function
, "done") == 0)
7030 ELEMENT_LOOP (PCB
->Data
);
7032 if (TEST_FLAG (FOUNDFLAG
, element
))
7034 CLEAR_FLAG (FOUNDFLAG
, element
);
7036 else if (! EMPTY_STRING_P (NAMEONPCB_NAME (element
)))
7038 /* Unnamed elements should remain untouched */
7039 SET_FLAG (SELECTEDFLAG
, element
);
7043 if (number_of_footprints_not_found
> 0)
7044 gui
->confirm_dialog ("Not all requested footprints were found.\n"
7045 "See the message log for details",
7050 if (strcasecmp (function
, "need") != 0)
7051 AFAIL (elementlist
);
7054 AFAIL (elementlist
);
7063 args
[0] = footprint
;
7068 printf(" ... footprint = %s\n", footprint
);
7069 printf(" ... refdes = %s\n", refdes
);
7070 printf(" ... value = %s\n", value
);
7073 e
= find_element_by_refdes (refdes
);
7080 printf(" ... Footprint not on board, need to add it.\n");
7082 /* Not on board, need to add it. */
7083 if (LoadFootprint(argc
, args
, x
, y
))
7085 number_of_footprints_not_found
++;
7089 nx
= PCB
->MaxWidth
/ 2;
7090 ny
= PCB
->MaxHeight
/ 2;
7091 d
= MIN (PCB
->MaxWidth
, PCB
->MaxHeight
) / 10;
7093 nx
= parse_layout_attribute_units ("import::newX", nx
);
7094 ny
= parse_layout_attribute_units ("import::newY", ny
);
7095 d
= parse_layout_attribute_units ("import::disperse", d
);
7099 nx
+= rand () % (d
*2) - d
;
7100 ny
+= rand () % (d
*2) - d
;
7105 if (nx
>= PCB
->MaxWidth
)
7106 nx
= PCB
->MaxWidth
- 1;
7109 if (ny
>= PCB
->MaxHeight
)
7110 ny
= PCB
->MaxHeight
- 1;
7112 /* Place components onto center of board. */
7113 if (CopyPastebufferToLayout (nx
, ny
))
7114 SetChangedFlag (true);
7117 else if (e
&& DESCRIPTION_NAME(e
) && strcmp (DESCRIPTION_NAME(e
), footprint
) != 0)
7120 printf(" ... Footprint on board, but different from footprint loaded.\n");
7126 /* Different footprint, we need to swap them out. */
7127 if (LoadFootprint(argc
, args
, x
, y
))
7129 number_of_footprints_not_found
++;
7133 er
= ElementOrientation (e
);
7134 pe
= PASTEBUFFER
->Data
->Element
->data
;
7136 MirrorElementCoordinates (PASTEBUFFER
->Data
, pe
, pe
->MarkY
*2 - PCB
->MaxHeight
);
7137 pr
= ElementOrientation (pe
);
7143 RotateElementLowLevel (PASTEBUFFER
->Data
, pe
, pe
->MarkX
, pe
->MarkY
, (er
-pr
+4)%4);
7145 for (i
=0; i
<MAX_ELEMENTNAMES
; i
++)
7147 pe
->Name
[i
].X
= e
->Name
[i
].X
- mx
+ pe
->MarkX
;
7148 pe
->Name
[i
].Y
= e
->Name
[i
].Y
- my
+ pe
->MarkY
;
7149 pe
->Name
[i
].Direction
= e
->Name
[i
].Direction
;
7150 pe
->Name
[i
].Scale
= e
->Name
[i
].Scale
;
7155 if (CopyPastebufferToLayout (mx
, my
))
7156 SetChangedFlag (true);
7159 /* Now reload footprint */
7160 element_cache
= NULL
;
7161 e
= find_element_by_refdes (refdes
);
7163 old
= ChangeElementText (PCB
, PCB
->Data
, e
, NAMEONPCB_INDEX
, strdup (refdes
));
7166 old
= ChangeElementText (PCB
, PCB
->Data
, e
, VALUE_INDEX
, strdup (value
));
7170 SET_FLAG (FOUNDFLAG
, e
);
7173 printf(" ... Leaving ActionElementList.\n");
7179 /* ---------------------------------------------------------------- */
7180 static const char elementsetattr_syntax
[] = "ElementSetAttr(refdes,name[,value])";
7182 static const char elementsetattr_help
[] = "Sets or clears an element-specific attribute.";
7184 /* %start-doc actions elementsetattr
7186 If a value is specified, the named attribute is added (if not already
7187 present) or changed (if it is) to the given value. If the value is
7188 not specified, the given attribute is removed if present.
7193 ActionElementSetAttr (int argc
, char **argv
, Coord x
, Coord y
)
7195 ElementType
*e
= NULL
;
7196 char *refdes
, *name
, *value
;
7197 AttributeType
*attr
;
7201 AFAIL (changepinname
);
7208 ELEMENT_LOOP (PCB
->Data
);
7210 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
7220 Message(_("Cannot change attribute of %s - element not found\n"), refdes
);
7224 attr
= lookup_attr (&e
->Attributes
, name
);
7229 attr
->value
= strdup (value
);
7231 if (attr
&& ! value
)
7233 delete_attr (& e
->Attributes
, attr
);
7237 CreateNewAttribute (& e
->Attributes
, name
, value
);
7243 /* ---------------------------------------------------------------- */
7244 static const char execcommand_syntax
[] = "ExecCommand(command)";
7246 static const char execcommand_help
[] = "Runs a command.";
7248 /* %start-doc actions execcommand
7250 Runs the given command, which is a system executable.
7255 ActionExecCommand (int argc
, char **argv
, Coord x
, Coord y
)
7261 AFAIL (execcommand
);
7266 if (system (command
))
7271 /* ---------------------------------------------------------------- */
7274 pcb_spawnvp (char **argv
)
7276 #ifdef HAVE__SPAWNVP
7277 int result
= _spawnvp (_P_WAIT
, argv
[0], (const char * const *) argv
);
7288 Message(_("Cannot fork!"));
7294 execvp (argv
[0], argv
);
7307 /* ---------------------------------------------------------------- */
7309 * Creates a new temporary file name. Hopefully the operating system
7310 * provides a mkdtemp() function to securily create a temporary
7311 * directory with mode 0700. If so then that directory is created and
7312 * the returned string is made up of the directory plus the name
7313 * variable. For example:
7315 * tempfile_name_new ("myfile") might return
7316 * "/var/tmp/pcb.123456/myfile".
7318 * If mkdtemp() is not available then 'name' is ignored and the
7319 * insecure tmpnam() function is used.
7321 * Files/names created with tempfile_name_new() should be unlinked
7322 * with tempfile_unlink to make sure the temporary directory is also
7323 * removed when mkdtemp() is used.
7326 tempfile_name_new (char * name
)
7328 char *tmpfile
= NULL
;
7330 char *tmpdir
, *mytmpdir
;
7334 assert ( name
!= NULL
);
7337 #define TEMPLATE "pcb.XXXXXXXX"
7340 tmpdir
= getenv ("TMPDIR");
7342 /* FIXME -- what about win32? */
7343 if (tmpdir
== NULL
) {
7347 mytmpdir
= (char *) malloc (sizeof(char) *
7352 if (mytmpdir
== NULL
) {
7353 fprintf (stderr
, "%s(): malloc failed()\n", __FUNCTION__
);
7358 (void)strcat (mytmpdir
, tmpdir
);
7359 (void)strcat (mytmpdir
, PCB_DIR_SEPARATOR_S
);
7360 (void)strcat (mytmpdir
, TEMPLATE
);
7361 if (mkdtemp (mytmpdir
) == NULL
) {
7362 fprintf (stderr
, "%s(): mkdtemp (\"%s\") failed\n", __FUNCTION__
, mytmpdir
);
7368 len
= strlen (mytmpdir
) + /* the temp directory name */
7369 1 + /* the directory sep. */
7370 strlen (name
) + /* the file name */
7371 1 /* the \0 termination */
7374 tmpfile
= (char *) malloc (sizeof (char) * len
);
7377 (void)strcat (tmpfile
, mytmpdir
);
7378 (void)strcat (tmpfile
, PCB_DIR_SEPARATOR_S
);
7379 (void)strcat (tmpfile
, name
);
7385 * tmpnam() uses a static buffer so strdup() the result right away
7386 * in case someone decides to create multiple temp names.
7388 tmpfile
= strdup (tmpnam (NULL
));
7391 /* Guile doesn't like \ separators */
7393 for (c
= tmpfile
; *c
; c
++)
7403 /* ---------------------------------------------------------------- */
7405 * Unlink a temporary file. If we have mkdtemp() then our temp file
7406 * lives in a temporary directory and we need to remove that directory
7410 tempfile_unlink (char * name
)
7413 /* SDB says: Want to keep old temp files for examiniation when debugging */
7422 /* it is possible that the file was never created so it is OK if the
7425 /* now figure out the directory name to remove */
7426 e
= strlen (name
) - 1;
7427 while (e
> 0 && name
[e
] != PCB_DIR_SEPARATOR_C
) {e
--;}
7429 dname
= strdup (name
);
7433 * at this point, e *should* point to the end of the directory part
7434 * but lets make sure.
7437 rc2
= rmdir (dname
);
7443 fprintf (stderr
, _("%s(): Unable to determine temp directory name from the temp file\n"),
7445 fprintf (stderr
, "%s(): \"%s\"\n",
7446 __FUNCTION__
, name
);
7450 /* name was allocated with malloc */
7455 * FIXME - should also return -1 if the temp file exists and was not
7463 int rc
= unlink (name
);
7466 fprintf (stderr
, _("Failed to unlink \"%s\"\n"), name
);
7477 /* ---------------------------------------------------------------- */
7478 static const char import_syntax
[] =
7480 "Import([gnetlist|make[,source,source,...]])\n"
7481 "Import(setnewpoint[,(mark|center|X,Y)])\n"
7482 "Import(setdisperse,D,units)\n";
7484 static const char import_help
[] = "Import schematics.";
7486 /* %start-doc actions Import
7488 Imports element and netlist data from the schematics (or some other
7489 source). The first parameter, which is optional, is the mode. If not
7490 specified, the @code{import::mode} attribute in the PCB is used.
7491 @code{gnetlist} means gnetlist is used to obtain the information from
7492 the schematics. @code{make} invokes @code{make}, assuming the user
7493 has a @code{Makefile} in the current directory. The @code{Makefile}
7494 will be invoked with the following variables set:
7499 The name of the .pcb file
7502 A space-separated list of source files
7505 The name of the file in which to put the command script, which may
7506 contain any @pcb{} actions. By default, this is a temporary file
7507 selected by @pcb{}, but if you specify an @code{import::outfile}
7508 attribute, that file name is used instead (and not automatically
7509 deleted afterwards).
7513 The target specified to be built is the first of these that apply:
7518 The target specified by an @code{import::target} attribute.
7521 The output file specified by an @code{import::outfile} attribute.
7524 If nothing else is specified, the target is @code{pcb_import}.
7528 If you specify an @code{import::makefile} attribute, then "-f <that
7529 file>" will be added to the command line.
7531 If you specify the mode, you may also specify the source files
7532 (schematics). If you do not specify any, the list of schematics is
7533 obtained by reading the @code{import::src@var{N}} attributes (like
7534 @code{import::src0}, @code{import::src1}, etc).
7536 For compatibility with future extensions to the import file format,
7537 the generated file @emph{must not} start with the two characters
7540 If a temporary file is needed the @code{TMPDIR} environment variable
7541 is used to select its location.
7543 Note that the programs @code{gnetlist} and @code{make} may be
7544 overridden by the user via the @code{make-program} and @code{gnetlist}
7545 @code{pcb} settings (i.e. in @code{~/.pcb/settings} or on the command
7548 If @pcb{} cannot determine which schematic(s) to import from, the GUI
7549 is called to let user choose (see @code{ImportGUI()}).
7551 Note that Import() doesn't delete anything - after an Import, elements
7552 which shouldn't be on the board are selected and may be removed once
7553 it's determined that the deletion is appropriate.
7555 If @code{Import()} is called with @code{setnewpoint}, then the location
7556 of new components can be specified. This is where parts show up when
7557 they're added to the board. The default is the center of the board.
7561 @item Import(setnewpoint)
7563 Prompts the user to click on the board somewhere, uses that point. If
7564 called by a hotkey, uses the current location of the crosshair.
7566 @item Import(setnewpoint,mark)
7568 Uses the location of the mark. If no mark is present, the point is
7571 @item Import(setnewpoint,center)
7573 Resets the point to the center of the board.
7575 @item Import(setnewpoint,X,Y,units)
7577 Sets the point to the specific coordinates given. Example:
7578 @code{Import(setnewpoint,50,25,mm)}
7582 Note that the X and Y locations are stored in attributes named
7583 @code{import::newX} and @code{import::newY} so you could change them
7584 manually if you wished.
7586 Calling @code{Import(setdisperse,D,units)} sets how much the newly
7587 placed elements are dispersed relative to the set point. For example,
7588 @code{Import(setdisperse,10,mm)} will offset each part randomly up to
7589 10mm away from the point. The default dispersion is 1/10th of the
7590 smallest board dimension. Dispersion is saved in the
7591 @code{import::disperse} attribute.
7596 ActionImport (int argc
, char **argv
, Coord x
, Coord y
)
7599 char **sources
= NULL
;
7603 printf("ActionImport: =========== Entering ActionImport ============\n");
7608 if (mode
&& strcasecmp (mode
, "setdisperse") == 0)
7617 const char *as
= AttributeGet (PCB
, "import::disperse");
7618 ds
= gui
->prompt_for(_("Enter dispersion:"), as
? as
: "0");
7622 sprintf(buf
, "%s%s", ds
, units
);
7623 AttributePut (PCB
, "import::disperse", buf
);
7626 AttributePut (PCB
, "import::disperse", ds
);
7627 if (ARG (1) == NULL
)
7632 if (mode
&& strcasecmp (mode
, "setnewpoint") == 0)
7634 const char *xs
, *ys
, *units
;
7644 gui
->get_coords (_("Click on a location"), &x
, &y
);
7646 else if (strcasecmp (xs
, "center") == 0)
7648 AttributeRemove (PCB
, "import::newX");
7649 AttributeRemove (PCB
, "import::newY");
7652 else if (strcasecmp (xs
, "mark") == 0)
7662 x
= GetValue (xs
, units
, NULL
);
7663 y
= GetValue (ys
, units
, NULL
);
7667 Message (_("Bad syntax for Import(setnewpoint)"));
7671 pcb_sprintf (buf
, "%$ms", x
);
7672 AttributePut (PCB
, "import::newX", buf
);
7673 pcb_sprintf (buf
, "%$ms", y
);
7674 AttributePut (PCB
, "import::newY", buf
);
7679 mode
= AttributeGet (PCB
, "import::mode");
7686 nsources
= argc
- 1;
7697 sprintf(sname
, "import::src%d", nsources
);
7698 src
= AttributeGet (PCB
, sname
);
7703 sources
= (char **) malloc ((nsources
+ 1) * sizeof (char *));
7707 sprintf(sname
, "import::src%d", nsources
);
7708 src
= AttributeGet (PCB
, sname
);
7709 sources
[nsources
] = src
;
7716 /* Replace .pcb with .sch and hope for the best. */
7717 char *pcbname
= PCB
->Filename
;
7719 char *dot
, *slash
, *bslash
;
7722 return hid_action("ImportGUI");
7724 schname
= (char *) malloc (strlen(pcbname
) + 5);
7725 strcpy (schname
, pcbname
);
7726 dot
= strchr (schname
, '.');
7727 slash
= strchr (schname
, '/');
7728 bslash
= strchr (schname
, '\\');
7729 if (dot
&& slash
&& dot
< slash
)
7731 if (dot
&& bslash
&& dot
< bslash
)
7735 strcat (schname
, ".sch");
7737 if (access (schname
, F_OK
))
7740 return hid_action("ImportGUI");
7743 sources
= (char **) malloc (2 * sizeof (char *));
7744 sources
[0] = schname
;
7749 if (strcasecmp (mode
, "gnetlist") == 0)
7751 char *tmpfile
= tempfile_name_new ("gnetlist_output");
7755 if (tmpfile
== NULL
) {
7756 Message (_("Could not create temp file"));
7760 cmd
= (char **) malloc ((7 + nsources
) * sizeof (char *));
7761 cmd
[0] = Settings
.GnetlistProgram
;
7767 for (i
=0; i
<nsources
; i
++)
7768 cmd
[6+i
] = sources
[i
];
7769 cmd
[6+nsources
] = NULL
;
7772 printf("ActionImport: =========== About to run gnetlist ============\n");
7773 printf("%s %s %s %s %s %s %s ...\n",
7774 cmd
[0], cmd
[1], cmd
[2], cmd
[3], cmd
[4], cmd
[5], cmd
[6]);
7777 if (pcb_spawnvp (cmd
))
7784 printf("ActionImport: =========== About to run ActionExecuteFile, file = %s ============\n", tmpfile
);
7789 ActionExecuteFile (1, cmd
, 0, 0);
7792 tempfile_unlink (tmpfile
);
7794 else if (strcasecmp (mode
, "make") == 0)
7796 int must_free_tmpfile
= 0;
7802 char *user_outfile
= NULL
;
7803 char *user_makefile
= NULL
;
7804 char *user_target
= NULL
;
7807 user_outfile
= AttributeGet (PCB
, "import::outfile");
7808 user_makefile
= AttributeGet (PCB
, "import::makefile");
7809 user_target
= AttributeGet (PCB
, "import::target");
7810 if (user_outfile
&& !user_target
)
7811 user_target
= user_outfile
;
7814 tmpfile
= user_outfile
;
7817 tmpfile
= tempfile_name_new ("gnetlist_output");
7818 if (tmpfile
== NULL
) {
7819 Message (_("Could not create temp file"));
7822 must_free_tmpfile
= 1;
7825 srclen
= sizeof("SRCLIST=") + 2;
7826 for (i
=0; i
<nsources
; i
++)
7827 srclen
+= strlen (sources
[i
]) + 2;
7828 srclist
= (char *) malloc (srclen
);
7829 strcpy (srclist
, "SRCLIST=");
7830 for (i
=0; i
<nsources
; i
++)
7833 strcat (srclist
, " ");
7834 strcat (srclist
, sources
[i
]);
7837 cmd
[0] = Settings
.MakeProgram
;
7839 cmd
[2] = Concat ("PCB=", PCB
->Filename
, NULL
);
7841 cmd
[4] = Concat ("OUT=", tmpfile
, NULL
);
7846 cmd
[i
++] = user_makefile
;
7848 cmd
[i
++] = user_target
? user_target
: (char *)"pcb_import";
7851 if (pcb_spawnvp (cmd
))
7853 if (must_free_tmpfile
)
7863 ActionExecuteFile (1, cmd
, 0, 0);
7868 if (must_free_tmpfile
)
7869 tempfile_unlink (tmpfile
);
7873 Message (_("Unknown import mode: %s\n"), mode
);
7878 AddAllRats (false, NULL
);
7881 printf("ActionImport: =========== Leaving ActionImport ============\n");
7887 /* ------------------------------------------------------------ */
7889 static const char attributes_syntax
[] =
7890 "Attributes(Layout|Layer|Element)\n"
7891 "Attributes(Layer,layername)";
7893 static const char attributes_help
[] =
7894 "Let the user edit the attributes of the layout, current or given\n"
7895 "layer, or selected element.";
7897 /* %start-doc actions Attributes
7899 This just pops up a dialog letting the user edit the attributes of the
7900 pcb, an element, or a layer.
7906 ActionAttributes (int argc
, char **argv
, Coord x
, Coord y
)
7908 char *function
= ARG (0);
7909 char *layername
= ARG (1);
7915 if (!gui
->edit_attributes
)
7917 Message (_("This GUI doesn't support Attribute Editing\n"));
7921 switch (GetFunctionID (function
))
7925 gui
->edit_attributes("Layout Attributes", &(PCB
->Attributes
));
7931 LayerType
*layer
= CURRENT
;
7936 for (i
=0; i
<max_copper_layer
; i
++)
7937 if (strcmp (PCB
->Data
->Layer
[i
].Name
, layername
) == 0)
7939 layer
= & (PCB
->Data
->Layer
[i
]);
7944 Message (_("No layer named %s\n"), layername
);
7948 buf
= (char *) malloc (strlen (layer
->Name
) + strlen ("Layer X Attributes"));
7949 sprintf (buf
, "Layer %s Attributes", layer
->Name
);
7950 gui
->edit_attributes(buf
, &(layer
->Attributes
));
7958 ElementType
*e
= NULL
;
7959 ELEMENT_LOOP (PCB
->Data
);
7961 if (TEST_FLAG (SELECTEDFLAG
, element
))
7970 Message (_("Too many elements selected\n"));
7976 gui
->get_coords (_("Click on an element"), &x
, &y
);
7978 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
7979 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
7980 e
= (ElementType
*) ptrtmp
;
7983 Message (_("No element found there\n"));
7988 if (NAMEONPCB_NAME(e
))
7990 buf
= (char *) malloc (strlen (NAMEONPCB_NAME(e
)) + strlen ("Element X Attributes"));
7991 sprintf(buf
, "Element %s Attributes", NAMEONPCB_NAME(e
));
7995 buf
= strdup ("Unnamed Element Attributes");
7997 gui
->edit_attributes(buf
, &(e
->Attributes
));
8009 /* --------------------------------------------------------------------------- */
8011 HID_Action action_action_list
[] = {
8012 {"AddRats", 0, ActionAddRats
,
8013 addrats_help
, addrats_syntax
}
8015 {"Attributes", 0, ActionAttributes
,
8016 attributes_help
, attributes_syntax
}
8018 {"Atomic", 0, ActionAtomic
,
8019 atomic_help
, atomic_syntax
}
8021 {"AutoPlaceSelected", 0, ActionAutoPlaceSelected
,
8022 autoplace_help
, autoplace_syntax
}
8024 {"AutoRoute", 0, ActionAutoRoute
,
8025 autoroute_help
, autoroute_syntax
}
8027 {"ChangeClearSize", 0, ActionChangeClearSize
,
8028 changeclearsize_help
, changeclearsize_syntax
}
8030 {"ChangeDrillSize", 0, ActionChange2ndSize
,
8031 changedrillsize_help
, changedrillsize_syntax
}
8033 {"ChangeHole", 0, ActionChangeHole
,
8034 changehold_help
, changehold_syntax
}
8036 {"ChangeJoin", 0, ActionChangeJoin
,
8037 changejoin_help
, changejoin_syntax
}
8039 {"ChangeName", 0, ActionChangeName
,
8040 changename_help
, changename_syntax
}
8042 {"ChangePaste", 0, ActionChangePaste
,
8043 changepaste_help
, changepaste_syntax
}
8045 {"ChangePinName", 0, ActionChangePinName
,
8046 changepinname_help
, changepinname_syntax
}
8048 {"ChangeSize", 0, ActionChangeSize
,
8049 changesize_help
, changesize_syntax
}
8051 {"ChangeSquare", 0, ActionChangeSquare
,
8052 changesquare_help
, changesquare_syntax
}
8054 {"ChangeOctagon", 0, ActionChangeOctagon
,
8055 changeoctagon_help
, changeoctagon_syntax
}
8057 {"ClearSquare", 0, ActionClearSquare
,
8058 clearsquare_help
, clearsquare_syntax
}
8060 {"ClearOctagon", 0, ActionClearOctagon
,
8061 clearoctagon_help
, clearoctagon_syntax
}
8063 {"Connection", 0, ActionConnection
,
8064 connection_help
, connection_syntax
}
8066 {"Delete", 0, ActionDelete
,
8067 delete_help
, delete_syntax
}
8069 {"DeleteRats", 0, ActionDeleteRats
,
8070 deleterats_help
, deleterats_syntax
}
8072 {"DisperseElements", 0, ActionDisperseElements
,
8073 disperseelements_help
, disperseelements_syntax
}
8075 {"Display", 0, ActionDisplay
,
8076 display_help
, display_syntax
}
8078 {"DRC", 0, ActionDRCheck
,
8079 drc_help
, drc_syntax
}
8081 {"DumpLibrary", 0, ActionDumpLibrary
,
8082 dumplibrary_help
, dumplibrary_syntax
}
8084 {"ExecuteFile", 0, ActionExecuteFile
,
8085 executefile_help
, executefile_syntax
}
8087 {"Flip", N_("Click on Object or Flip Point"), ActionFlip
,
8088 flip_help
, flip_syntax
}
8090 {"LoadFrom", 0, ActionLoadFrom
,
8091 loadfrom_help
, loadfrom_syntax
}
8093 {"MarkCrosshair", 0, ActionMarkCrosshair
,
8094 markcrosshair_help
, markcrosshair_syntax
}
8096 {"Message", 0, ActionMessage
,
8097 message_help
, message_syntax
}
8099 {"MinMaskGap", 0, ActionMinMaskGap
,
8100 minmaskgap_help
, minmaskgap_syntax
}
8102 {"MinClearGap", 0, ActionMinClearGap
,
8103 mincleargap_help
, mincleargap_syntax
}
8105 {"Mode", 0, ActionMode
,
8106 mode_help
, mode_syntax
}
8108 {"MorphPolygon", 0, ActionMorphPolygon
,
8109 morphpolygon_help
, morphpolygon_syntax
}
8111 {"PasteBuffer", 0, ActionPasteBuffer
,
8112 pastebuffer_help
, pastebuffer_syntax
}
8114 {"Quit", 0, ActionQuit
,
8115 quit_help
, quit_syntax
}
8117 {"RemoveSelected", 0, ActionRemoveSelected
,
8118 removeselected_help
, removeselected_syntax
}
8120 {"Renumber", 0, ActionRenumber
,
8121 renumber_help
, renumber_syntax
}
8123 {"RipUp", 0, ActionRipUp
,
8124 ripup_help
, ripup_syntax
}
8126 {"Select", 0, ActionSelect
,
8127 select_help
, select_syntax
}
8129 {"Unselect", 0, ActionUnselect
,
8130 unselect_help
, unselect_syntax
}
8132 {"SaveSettings", 0, ActionSaveSettings
,
8133 savesettings_help
, savesettings_syntax
}
8135 {"SaveTo", 0, ActionSaveTo
,
8136 saveto_help
, saveto_syntax
}
8138 {"SetSquare", 0, ActionSetSquare
,
8139 setsquare_help
, setsquare_syntax
}
8141 {"SetOctagon", 0, ActionSetOctagon
,
8142 setoctagon_help
, setoctagon_syntax
}
8144 {"SetThermal", 0, ActionSetThermal
,
8145 setthermal_help
, setthermal_syntax
}
8147 {"SetValue", 0, ActionSetValue
,
8148 setvalue_help
, setvalue_syntax
}
8150 {"ToggleHideName", 0, ActionToggleHideName
,
8151 togglehidename_help
, togglehidename_syntax
}
8153 {"Undo", 0, ActionUndo
,
8154 undo_help
, undo_syntax
}
8156 {"Redo", 0, ActionRedo
,
8157 redo_help
, redo_syntax
}
8159 {"SetSame", N_("Select item to use attributes from"), ActionSetSame
,
8160 setsame_help
, setsame_syntax
}
8162 {"SetFlag", 0, ActionSetFlag
,
8163 setflag_help
, setflag_syntax
}
8165 {"ClrFlag", 0, ActionClrFlag
,
8166 clrflag_help
, clrflag_syntax
}
8168 {"ChangeFlag", 0, ActionChangeFlag
,
8169 changeflag_help
, changeflag_syntax
}
8171 {"Polygon", 0, ActionPolygon
,
8172 polygon_help
, polygon_syntax
}
8174 {"RouteStyle", 0, ActionRouteStyle
,
8175 routestyle_help
, routestyle_syntax
}
8177 {"MoveObject", N_("Select an Object"), ActionMoveObject
,
8178 moveobject_help
, moveobject_syntax
}
8180 {"MoveToCurrentLayer", 0, ActionMoveToCurrentLayer
,
8181 movetocurrentlayer_help
, movetocurrentlayer_syntax
}
8183 {"New", 0, ActionNew
,
8184 new_help
, new_syntax
}
8186 {"pscalib", 0, ActionPSCalib
}
8188 {"ElementList", 0, ActionElementList
,
8189 elementlist_help
, elementlist_syntax
}
8191 {"ElementSetAttr", 0, ActionElementSetAttr
,
8192 elementsetattr_help
, elementsetattr_syntax
}
8194 {"ExecCommand", 0, ActionExecCommand
,
8195 execcommand_help
, execcommand_syntax
}
8197 {"Import", 0, ActionImport
,
8198 import_help
, import_syntax
}
8202 REGISTER_ACTIONS (action_action_list
)