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
))
1263 CreateDrawnLineOnLayer (CURRENT
,
1264 Crosshair
.AttachedLine
.Point1
.X
,
1265 Crosshair
.AttachedLine
.Point1
.Y
,
1266 Crosshair
.AttachedLine
.Point2
.X
,
1267 Crosshair
.AttachedLine
.Point2
.Y
,
1268 Settings
.LineThickness
,
1269 2 * Settings
.Keepaway
,
1270 MakeFlags (line_flags
))) != NULL
)
1274 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1275 DrawLine (CURRENT
, line
);
1277 /* place a via if vias are visible, the layer is
1278 in a new group since the last line and there
1279 isn't a pin already here */
1280 if (PCB
->ViaOn
&& GetLayerGroupNumberByPointer (CURRENT
) !=
1281 GetLayerGroupNumberByPointer (lastLayer
) &&
1282 SearchObjectByLocation (PIN_TYPES
, &ptr1
, &ptr2
, &ptr3
,
1283 Crosshair
.AttachedLine
.Point1
.X
,
1284 Crosshair
.AttachedLine
.Point1
.Y
,
1285 Settings
.ViaThickness
/ 2) ==
1288 CreateNewVia (PCB
->Data
,
1289 Crosshair
.AttachedLine
.Point1
.X
,
1290 Crosshair
.AttachedLine
.Point1
.Y
,
1291 Settings
.ViaThickness
,
1292 2 * Settings
.Keepaway
, 0,
1293 Settings
.ViaDrillingHole
, NULL
,
1294 NoFlags ())) != NULL
)
1296 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1299 /* copy the coordinates */
1300 Crosshair
.AttachedLine
.Point1
.X
=
1301 Crosshair
.AttachedLine
.Point2
.X
;
1302 Crosshair
.AttachedLine
.Point1
.Y
=
1303 Crosshair
.AttachedLine
.Point2
.Y
;
1304 IncrementUndoSerialNumber ();
1305 lastLayer
= CURRENT
;
1307 if (PCB
->Clipping
&& (Note
.X
!= Crosshair
.AttachedLine
.Point2
.X
1309 Crosshair
.AttachedLine
.Point2
.Y
))
1312 CreateDrawnLineOnLayer (CURRENT
,
1313 Crosshair
.AttachedLine
.Point2
.X
,
1314 Crosshair
.AttachedLine
.Point2
.Y
,
1316 Settings
.LineThickness
,
1317 2 * Settings
.Keepaway
,
1318 MakeFlags (line_flags
))) != NULL
)
1321 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1322 IncrementUndoSerialNumber ();
1323 DrawLine (CURRENT
, line
);
1325 /* move to new start point */
1326 Crosshair
.AttachedLine
.Point1
.X
= Note
.X
;
1327 Crosshair
.AttachedLine
.Point1
.Y
= Note
.Y
;
1328 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1329 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1330 if (TEST_FLAG (SWAPSTARTDIRFLAG
, PCB
))
1335 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && !TEST_SILK_LAYER (CURRENT
))
1336 LookupConnection (Note
.X
, Note
.Y
, true, 1, CONNECTEDFLAG
, false);
1341 case RECTANGLE_MODE
:
1342 /* do update of position */
1345 /* create rectangle if both corners are determined
1346 * and width, height are != 0
1348 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
1349 Crosshair
.AttachedBox
.Point1
.X
!= Crosshair
.AttachedBox
.Point2
.X
&&
1350 Crosshair
.AttachedBox
.Point1
.Y
!= Crosshair
.AttachedBox
.Point2
.Y
)
1352 PolygonType
*polygon
;
1354 int flags
= CLEARPOLYFLAG
;
1355 if (TEST_FLAG (NEWFULLPOLYFLAG
, PCB
))
1356 flags
|= FULLPOLYFLAG
;
1357 if ((polygon
= CreateNewPolygonFromRectangle (CURRENT
,
1359 AttachedBox
.Point1
.X
,
1361 AttachedBox
.Point1
.Y
,
1363 AttachedBox
.Point2
.X
,
1365 AttachedBox
.Point2
.Y
,
1370 AddObjectToCreateUndoList (POLYGON_TYPE
, CURRENT
,
1372 IncrementUndoSerialNumber ();
1373 DrawPolygon (CURRENT
, polygon
);
1377 /* reset state to 'first corner' */
1378 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
1386 if ((string
= gui
->prompt_for (_("Enter text:"), "")) != NULL
)
1388 if (strlen(string
) > 0)
1391 int flag
= CLEARLINEFLAG
;
1393 if (GetLayerGroupNumberByNumber (INDEXOFCURRENT
) ==
1394 GetLayerGroupNumberBySide (BOTTOM_SIDE
))
1395 flag
|= ONSOLDERFLAG
;
1396 if ((text
= CreateNewText (CURRENT
, &PCB
->Font
, Note
.X
,
1397 Note
.Y
, 0, Settings
.TextScale
,
1398 string
, MakeFlags (flag
))) != NULL
)
1400 AddObjectToCreateUndoList (TEXT_TYPE
, CURRENT
, text
, text
);
1401 IncrementUndoSerialNumber ();
1402 DrawText (CURRENT
, text
);
1413 PointType
*points
= Crosshair
.AttachedPolygon
.Points
;
1414 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1416 /* do update of position; use the 'LINE_MODE' mechanism */
1419 /* check if this is the last point of a polygon */
1421 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1422 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1424 CopyAttachedPolygonToLayer ();
1429 /* create new point if it's the first one or if it's
1430 * different to the last one
1433 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1434 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1436 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1437 Crosshair
.AttachedLine
.Point2
.X
,
1438 Crosshair
.AttachedLine
.Point2
.Y
);
1440 /* copy the coordinates */
1441 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1442 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1447 case POLYGONHOLE_MODE
:
1449 switch (Crosshair
.AttachedObject
.State
)
1451 /* first notify, lookup object */
1453 Crosshair
.AttachedObject
.Type
=
1454 SearchScreen (Note
.X
, Note
.Y
, POLYGON_TYPE
,
1455 &Crosshair
.AttachedObject
.Ptr1
,
1456 &Crosshair
.AttachedObject
.Ptr2
,
1457 &Crosshair
.AttachedObject
.Ptr3
);
1459 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1461 if (TEST_FLAG (LOCKFLAG
, (PolygonType
*)
1462 Crosshair
.AttachedObject
.Ptr2
))
1464 Message (_("Sorry, the object is locked\n"));
1465 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1469 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1473 /* second notify, insert new point into object */
1476 PointType
*points
= Crosshair
.AttachedPolygon
.Points
;
1477 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1478 POLYAREA
*original
, *new_hole
, *result
;
1481 /* do update of position; use the 'LINE_MODE' mechanism */
1484 /* check if this is the last point of a polygon */
1486 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1487 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1489 /* Create POLYAREAs from the original polygon
1490 * and the new hole polygon */
1491 original
= PolygonToPoly ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
);
1492 new_hole
= PolygonToPoly (&Crosshair
.AttachedPolygon
);
1494 /* Subtract the hole from the original polygon shape */
1495 poly_Boolean_free (original
, new_hole
, &result
, PBO_SUB
);
1497 /* Convert the resulting polygon(s) into a new set of nodes
1498 * and place them on the page. Delete the original polygon.
1500 SaveUndoSerialNumber ();
1501 Flags
= ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
)->Flags
;
1502 PolyToPolygonsOnLayer (PCB
->Data
, (LayerType
*)Crosshair
.AttachedObject
.Ptr1
,
1504 RemoveObject (POLYGON_TYPE
,
1505 Crosshair
.AttachedObject
.Ptr1
,
1506 Crosshair
.AttachedObject
.Ptr2
,
1507 Crosshair
.AttachedObject
.Ptr3
);
1508 RestoreUndoSerialNumber ();
1509 IncrementUndoSerialNumber ();
1512 /* reset state of attached line */
1513 memset (&Crosshair
.AttachedPolygon
, 0, sizeof (PolygonType
));
1514 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
1520 /* create new point if it's the first one or if it's
1521 * different to the last one
1524 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1525 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1527 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1528 Crosshair
.AttachedLine
.Point2
.X
,
1529 Crosshair
.AttachedLine
.Point2
.Y
);
1531 /* copy the coordinates */
1532 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1533 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1542 case PASTEBUFFER_MODE
:
1544 TextType estr
[MAX_ELEMENTNAMES
];
1547 if (gui
->shift_is_pressed ())
1550 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1552 if (type
== ELEMENT_TYPE
)
1554 e
= (ElementType
*) ptr1
;
1559 memcpy (estr
, e
->Name
,
1560 MAX_ELEMENTNAMES
* sizeof (TextType
));
1561 for (i
= 0; i
< MAX_ELEMENTNAMES
; ++i
)
1562 estr
[i
].TextString
= estr
[i
].TextString
? strdup(estr
[i
].TextString
) : NULL
;
1567 if (CopyPastebufferToLayout (Note
.X
, Note
.Y
))
1568 SetChangedFlag (true);
1572 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1574 if (type
== ELEMENT_TYPE
&& ptr1
)
1577 e
= (ElementType
*) ptr1
;
1579 save_n
= NAME_INDEX (PCB
);
1581 for (i
= 0; i
< MAX_ELEMENTNAMES
; i
++)
1584 EraseElementName (e
);
1585 r_delete_entry (PCB
->Data
->name_tree
[i
],
1586 (BoxType
*) & (e
->Name
[i
]));
1587 memcpy (&(e
->Name
[i
]), &(estr
[i
]), sizeof (TextType
));
1588 e
->Name
[i
].Element
= e
;
1589 SetTextBoundingBox (&PCB
->Font
, &(e
->Name
[i
]));
1590 r_insert_entry (PCB
->Data
->name_tree
[i
],
1591 (BoxType
*) & (e
->Name
[i
]), 0);
1593 DrawElementName (e
);
1602 SearchScreen (Note
.X
, Note
.Y
, REMOVE_TYPES
, &ptr1
, &ptr2
,
1605 if (TEST_FLAG (LOCKFLAG
, (LineType
*) ptr2
))
1607 Message (_("Sorry, the object is locked\n"));
1610 if (type
== ELEMENT_TYPE
)
1612 RubberbandType
*ptr
;
1615 Crosshair
.AttachedObject
.RubberbandN
= 0;
1616 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
1617 ptr
= Crosshair
.AttachedObject
.Rubberband
;
1618 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
; i
++)
1621 EraseRat ((RatType
*) ptr
->Line
);
1622 if (TEST_FLAG (RUBBERENDFLAG
, ptr
->Line
))
1623 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
1624 ptr
->Line
, ptr
->Line
,
1627 TOGGLE_FLAG (RUBBERENDFLAG
, ptr
->Line
); /* only remove line once */
1631 RemoveObject (type
, ptr1
, ptr2
, ptr3
);
1632 IncrementUndoSerialNumber ();
1633 SetChangedFlag (true);
1638 RotateScreenObject (Note
.X
, Note
.Y
,
1639 gui
->shift_is_pressed ()? (SWAP_IDENT
?
1641 : (SWAP_IDENT
? 3 : 1));
1644 /* both are almost the same */
1647 switch (Crosshair
.AttachedObject
.State
)
1649 /* first notify, lookup object */
1652 int types
= (Settings
.Mode
== COPY_MODE
) ?
1653 COPY_TYPES
: MOVE_TYPES
;
1655 Crosshair
.AttachedObject
.Type
=
1656 SearchScreen (Note
.X
, Note
.Y
, types
,
1657 &Crosshair
.AttachedObject
.Ptr1
,
1658 &Crosshair
.AttachedObject
.Ptr2
,
1659 &Crosshair
.AttachedObject
.Ptr3
);
1660 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1662 if (Settings
.Mode
== MOVE_MODE
&&
1663 TEST_FLAG (LOCKFLAG
, (PinType
*)
1664 Crosshair
.AttachedObject
.Ptr2
))
1666 Message (_("Sorry, the object is locked\n"));
1667 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1670 AttachForCopy (Note
.X
, Note
.Y
);
1675 /* second notify, move or copy object */
1677 if (Settings
.Mode
== COPY_MODE
)
1678 CopyObject (Crosshair
.AttachedObject
.Type
,
1679 Crosshair
.AttachedObject
.Ptr1
,
1680 Crosshair
.AttachedObject
.Ptr2
,
1681 Crosshair
.AttachedObject
.Ptr3
,
1682 Note
.X
- Crosshair
.AttachedObject
.X
,
1683 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1686 MoveObjectAndRubberband (Crosshair
.AttachedObject
.Type
,
1687 Crosshair
.AttachedObject
.Ptr1
,
1688 Crosshair
.AttachedObject
.Ptr2
,
1689 Crosshair
.AttachedObject
.Ptr3
,
1690 Note
.X
- Crosshair
.AttachedObject
.X
,
1691 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1692 SetLocalRef (0, 0, false);
1694 SetChangedFlag (true);
1696 /* reset identifiers */
1697 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1698 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1703 /* insert a point into a polygon/line/... */
1704 case INSERTPOINT_MODE
:
1705 switch (Crosshair
.AttachedObject
.State
)
1707 /* first notify, lookup object */
1709 Crosshair
.AttachedObject
.Type
=
1710 SearchScreen (Note
.X
, Note
.Y
, INSERT_TYPES
,
1711 &Crosshair
.AttachedObject
.Ptr1
,
1712 &Crosshair
.AttachedObject
.Ptr2
,
1713 &Crosshair
.AttachedObject
.Ptr3
);
1715 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1717 if (TEST_FLAG (LOCKFLAG
, (PolygonType
*)
1718 Crosshair
.AttachedObject
.Ptr2
))
1720 Message (_("Sorry, the object is locked\n"));
1721 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1726 /* get starting point of nearest segment */
1727 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1730 (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
;
1732 GetLowestDistancePolygonPoint (fake
.poly
, Note
.X
,
1734 fake
.line
.Point1
= fake
.poly
->Points
[polyIndex
];
1735 fake
.line
.Point2
= fake
.poly
->Points
[
1736 prev_contour_point (fake
.poly
, polyIndex
)];
1737 Crosshair
.AttachedObject
.Ptr2
= &fake
.line
;
1740 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1741 InsertedPoint
= *AdjustInsertPoint ();
1746 /* second notify, insert new point into object */
1748 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1749 InsertPointIntoObject (POLYGON_TYPE
,
1750 Crosshair
.AttachedObject
.Ptr1
, fake
.poly
,
1752 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1754 InsertPointIntoObject (Crosshair
.AttachedObject
.Type
,
1755 Crosshair
.AttachedObject
.Ptr1
,
1756 Crosshair
.AttachedObject
.Ptr2
,
1758 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1759 SetChangedFlag (true);
1761 /* reset identifiers */
1762 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1763 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1771 /* --------------------------------------------------------------------------- */
1773 static const char atomic_syntax
[] = N_("Atomic(Save|Restore|Close|Block)");
1775 static const char atomic_help
[] = N_("Save or restore the undo serial number.");
1777 /* %start-doc actions Atomic
1779 This action allows making multiple-action bindings into an atomic
1780 operation that will be undone by a single Undo command. For example,
1781 to optimize rat lines, you'd delete the rats and re-add them. To
1782 group these into a single undo, you'd want the deletions and the
1783 additions to have the same undo serial number. So, you @code{Save},
1784 delete the rats, @code{Restore}, add the rats - using the same serial
1785 number as the deletes, then @code{Block}, which checks to see if the
1786 deletions or additions actually did anything. If not, the serial
1787 number is set to the saved number, as there's nothing to undo. If
1788 something did happen, the serial number is incremented so that these
1789 actions are counted as a single undo step.
1794 Saves the undo serial number.
1797 Returns it to the last saved number.
1800 Sets it to 1 greater than the last save.
1803 Does a Restore if there was nothing to undo, else does a Close.
1810 ActionAtomic (int argc
, char **argv
, Coord x
, Coord y
)
1815 switch (GetFunctionID (argv
[0]))
1818 SaveUndoSerialNumber ();
1821 RestoreUndoSerialNumber ();
1824 RestoreUndoSerialNumber ();
1825 IncrementUndoSerialNumber ();
1828 RestoreUndoSerialNumber ();
1830 IncrementUndoSerialNumber ();
1836 /* -------------------------------------------------------------------------- */
1838 static const char drc_syntax
[] = N_("DRC()");
1840 static const char drc_help
[] = N_("Invoke the DRC check.");
1842 /* %start-doc actions DRC
1844 Note that the design rule check uses the current board rule settings,
1845 not the current style settings.
1850 ActionDRCheck (int argc
, char **argv
, Coord x
, Coord y
)
1854 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1856 Message (_("%m+Rules are minspace %$mS, minoverlap %$mS "
1857 "minwidth %$mS, minsilk %$mS\n"
1858 "min drill %$mS, min annular ring %$mS\n"),
1859 Settings
.grid_unit
->allow
,
1860 PCB
->Bloat
, PCB
->Shrink
,
1861 PCB
->minWid
, PCB
->minSlk
,
1862 PCB
->minDrill
, PCB
->minRing
);
1865 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1868 Message (_("No DRC problems found.\n"));
1870 Message (_("Found %d design rule errors.\n"), count
);
1872 Message (_("Aborted DRC after %d design rule errors.\n"), -count
);
1877 /* -------------------------------------------------------------------------- */
1879 static const char dumplibrary_syntax
[] = N_("DumpLibrary()");
1881 static const char dumplibrary_help
[] =
1882 N_("Display the entire contents of the libraries.");
1884 /* %start-doc actions DumpLibrary
1890 ActionDumpLibrary (int argc
, char **argv
, Coord x
, Coord y
)
1894 printf ("**** Do not count on this format. It will change ****\n\n");
1895 printf ("MenuN = %d\n", Library
.MenuN
);
1896 printf ("MenuMax = %d\n", Library
.MenuMax
);
1897 for (i
= 0; i
< Library
.MenuN
; i
++)
1899 printf ("Library #%d:\n", i
);
1900 printf (" EntryN = %d\n", Library
.Menu
[i
].EntryN
);
1901 printf (" EntryMax = %d\n", Library
.Menu
[i
].EntryMax
);
1902 printf (" Name = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Name
));
1903 printf (" directory = \"%s\"\n",
1904 UNKNOWN (Library
.Menu
[i
].directory
));
1905 printf (" Style = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Style
));
1906 printf (" flag = %d\n", Library
.Menu
[i
].flag
);
1908 for (j
= 0; j
< Library
.Menu
[i
].EntryN
; j
++)
1910 printf (" #%4d: ", j
);
1911 if (Library
.Menu
[i
].Entry
[j
].Template
== (char *) -1)
1913 printf ("newlib: \"%s\"\n",
1914 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
));
1918 printf ("\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"\n",
1919 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
),
1920 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Template
),
1921 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Package
),
1922 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Value
),
1923 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Description
));
1931 /* -------------------------------------------------------------------------- */
1933 static const char flip_syntax
[] = N_("Flip(Object|Selected|SelectedElements)");
1935 static const char flip_help
[] =
1936 N_("Flip an element to the opposite side of the board.");
1938 /* %start-doc actions Flip
1940 Note that the location of the element will be symmetric about the
1941 cursor location; i.e. if the part you are pointing at will still be at
1942 the same spot once the element is on the other side. When flipping
1943 multiple elements, this retains their positions relative to each
1944 other, not their absolute positions on the board.
1949 ActionFlip (int argc
, char **argv
, Coord x
, Coord y
)
1951 char *function
= ARG (0);
1952 ElementType
*element
;
1958 switch (GetFunctionID (function
))
1961 if ((SearchScreen (x
, y
, ELEMENT_TYPE
,
1962 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
1964 element
= (ElementType
*) ptrtmp
;
1965 ChangeElementSide (element
, 2 * Crosshair
.Y
- PCB
->MaxHeight
);
1966 IncrementUndoSerialNumber ();
1971 case F_SelectedElements
:
1972 ChangeSelectedElementSide ();
1985 /* -------------------------------------------------------------------------- */
1987 static const char message_syntax
[] = N_("Message(message)");
1989 static const char message_help
[] = N_("Writes a message to the log window.");
1991 /* %start-doc actions Message
1993 This action displays a message to the log window. This action is primarily
1994 provided for use by other programs which may interface with PCB. If
1995 multiple arguments are given, each one is sent to the log window
1996 followed by a newline.
2001 ActionMessage (int argc
, char **argv
, Coord x
, Coord y
)
2008 for (i
= 0; i
< argc
; i
++)
2018 /* -------------------------------------------------------------------------- */
2020 static const char setthermal_syntax
[] =
2021 "SetThermal(Object|SelectedPins|SelectedVias|Selected, Style)";
2023 static const char setthermal_help
[] =
2024 N_("Set the thermal (on the current layer) of pins or vias to the given style.\n"
2025 "Style = 0 means no thermal.\n"
2026 "Style = 1 has diagonal fingers with sharp edges.\n"
2027 "Style = 2 has horizontal and vertical fingers with sharp edges.\n"
2028 "Style = 3 is a solid connection to the plane."
2029 "Style = 4 has diagonal fingers with rounded edges.\n"
2030 "Style = 5 has horizontal and vertical fingers with rounded edges.\n");
2032 /* %start-doc actions SetThermal
2034 This changes how/whether pins or vias connect to any rectangle or polygon
2035 on the current layer. The first argument can specify one object, or all
2036 selected pins, or all selected vias, or all selected pins and vias.
2037 The second argument specifies the style of connection.
2038 There are 5 possibilities:
2040 1 - 45 degree fingers with sharp edges,
2041 2 - horizontal & vertical fingers with sharp edges,
2042 3 - solid connection,
2043 4 - 45 degree fingers with rounded corners,
2044 5 - horizontal & vertical fingers with rounded corners.
2046 Pins and Vias may have thermals whether or not there is a polygon available
2047 to connect with. However, they will have no effect without the polygon.
2051 ActionSetThermal (int argc
, char **argv
, Coord x
, Coord y
)
2053 char *function
= ARG (0);
2054 char *style
= ARG (1);
2055 void *ptr1
, *ptr2
, *ptr3
;
2059 if (function
&& *function
&& style
&& *style
)
2063 kind
= GetValue (style
, NULL
, &absolute
);
2065 switch (GetFunctionID (function
))
2069 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGETHERMAL_TYPES
,
2070 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
2072 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, kind
);
2073 IncrementUndoSerialNumber ();
2077 case F_SelectedPins
:
2078 ChangeSelectedThermals (PIN_TYPE
, kind
);
2080 case F_SelectedVias
:
2081 ChangeSelectedThermals (VIA_TYPE
, kind
);
2084 case F_SelectedElements
:
2085 ChangeSelectedThermals (CHANGETHERMAL_TYPES
, kind
);
2100 /* ---------------------------------------------------------------------------
2101 * !!! no action routine !!!
2103 * event handler to set the cursor according to the X pointer position
2104 * called from inside main.c
2107 EventMoveCrosshair (int ev_x
, int ev_y
)
2109 #ifdef HAVE_LIBSTROKE
2112 StrokeBox
.X2
= ev_x
;
2113 StrokeBox
.Y2
= ev_y
;
2114 stroke_record (ev_x
, ev_y
);
2117 #endif /* HAVE_LIBSTROKE */
2118 if (MoveCrosshairAbsolute (ev_x
, ev_y
))
2120 /* update object position and cursor location */
2121 AdjustAttachedObjects ();
2122 notify_crosshair_change (true);
2126 /* --------------------------------------------------------------------------- */
2128 static const char setvalue_syntax
[] =
2129 N_("SetValue(Grid|Line|LineSize|Text|TextScale|ViaDrillingHole|Via|ViaSize, "
2132 static const char setvalue_help
[] =
2133 N_("Change various board-wide values and sizes.");
2135 /* %start-doc actions SetValue
2139 @item ViaDrillingHole
2140 Changes the diameter of the drill for new vias.
2143 Sets the grid spacing.
2147 Changes the thickness of new lines.
2151 Changes the diameter of new vias.
2155 Changes the size of new text.
2162 ActionSetValue (int argc
, char **argv
, Coord x
, Coord y
)
2164 char *function
= ARG (0);
2165 char *val
= ARG (1);
2166 char *units
= ARG (2);
2167 bool absolute
; /* flag for 'absolute' value */
2172 if (function
&& val
)
2174 value
= GetValue (val
, units
, &absolute
);
2175 switch (GetFunctionID (function
))
2177 case F_ViaDrillingHole
:
2178 SetViaDrillingHole (absolute
? value
:
2179 value
+ Settings
.ViaDrillingHole
,
2181 hid_action ("RouteStylesChanged");
2186 SetGrid (value
, false);
2190 value
= val
[0] == '-' ? -Settings
.increments
->grid
2191 : Settings
.increments
->grid
;
2192 /* On the way down, short against the minimum
2193 * PCB drawing unit */
2194 if ((value
+ PCB
->Grid
) < 1)
2196 else if (PCB
->Grid
== 1)
2197 SetGrid (value
, false);
2199 SetGrid (value
+ PCB
->Grid
, false);
2205 if (!absolute
&& value
== 0)
2206 value
= val
[0] == '-' ? -Settings
.increments
->line
2207 : Settings
.increments
->line
;
2208 SetLineSize (absolute
? value
: value
+ Settings
.LineThickness
);
2209 hid_action ("RouteStylesChanged");
2214 SetViaSize (absolute
? value
: value
+ Settings
.ViaThickness
, false);
2215 hid_action ("RouteStylesChanged");
2220 text_scale
= value
/ (double)FONT_CAPHEIGHT
* 100.;
2222 text_scale
+= Settings
.TextScale
;
2223 SetTextScale (text_scale
);
2237 /* --------------------------------------------------------------------------- */
2239 static const char quit_syntax
[] = N_("Quit()");
2241 static const char quit_help
[] = N_("Quits the application after confirming.");
2243 /* %start-doc actions Quit
2245 If you have unsaved changes, you will be prompted to confirm (or
2246 save) before quitting.
2251 ActionQuit (int argc
, char **argv
, Coord x
, Coord y
)
2253 char *force
= ARG (0);
2254 if (force
&& strcasecmp (force
, "force") == 0)
2259 if (!PCB
->Changed
|| gui
->close_confirm_dialog () == HID_CLOSE_CONFIRM_OK
)
2264 /* --------------------------------------------------------------------------- */
2266 static const char connection_syntax
[] =
2267 N_("Connection(Find|ResetLinesAndPolygons|ResetPinsAndVias|Reset)");
2269 static const char connection_help
[] =
2270 N_("Searches connections of the object at the cursor position.");
2272 /* %start-doc actions Connection
2274 Connections found with this action will be highlighted in the
2275 ``connected-color'' color and will have the ``found'' flag set.
2280 The net under the cursor is ``found''.
2282 @item ResetLinesAndPolygons
2283 Any ``found'' lines and polygons are marked ``not found''.
2285 @item ResetPinsAndVias
2286 Any ``found'' pins and vias are marked ``not found''.
2289 All ``found'' objects are marked ``not found''.
2296 ActionConnection (int argc
, char **argv
, Coord x
, Coord y
)
2298 char *function
= ARG (0);
2301 switch (GetFunctionID (function
))
2305 gui
->get_coords (_("Click on a connection"), &x
, &y
);
2306 LookupConnection (x
, y
, true, 1, CONNECTEDFLAG
, false);
2307 LookupConnection (x
, y
, true, 1, FOUNDFLAG
, true);
2311 case F_ResetLinesAndPolygons
:
2312 if (ClearFlagOnLinesAndPolygons (true, CONNECTEDFLAG
| FOUNDFLAG
))
2314 IncrementUndoSerialNumber ();
2319 case F_ResetPinsViasAndPads
:
2320 if (ClearFlagOnPinsViasAndPads (true, CONNECTEDFLAG
| FOUNDFLAG
))
2322 IncrementUndoSerialNumber ();
2328 if (ClearFlagOnAllObjects (true, CONNECTEDFLAG
| FOUNDFLAG
))
2330 IncrementUndoSerialNumber ();
2341 /* --------------------------------------------------------------------------- */
2343 static const char disperseelements_syntax
[] =
2344 N_("DisperseElements(All|Selected)");
2346 static const char disperseelements_help
[] = N_("Disperses elements.");
2348 /* %start-doc actions DisperseElements
2350 Normally this is used when starting a board, by selecting all elements
2351 and then dispersing them. This scatters the elements around the board
2352 so that you can pick individual ones, rather than have all the
2353 elements at the same 0,0 coordinate and thus impossible to choose
2358 #define GAP MIL_TO_COORD(100)
2361 ActionDisperseElements (int argc
, char **argv
, Coord x
, Coord y
)
2363 char *function
= ARG (0);
2368 int all
= 0, bad
= 0;
2370 if (!function
|| !*function
)
2376 switch (GetFunctionID (function
))
2393 AFAIL (disperseelements
);
2397 ELEMENT_LOOP (PCB
->Data
);
2400 * If we want to disperse selected elements, maybe we need smarter
2401 * code here to avoid putting components on top of others which
2402 * are not selected. For now, I'm assuming that this is typically
2403 * going to be used either with a brand new design or a scratch
2404 * design holding some new components
2406 if (!TEST_FLAG (LOCKFLAG
, element
) && (all
|| TEST_FLAG (SELECTEDFLAG
, element
)))
2409 /* figure out how much to move the element */
2410 dx
= minx
- element
->BoundingBox
.X1
;
2412 /* snap to the grid */
2413 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2416 * and add one grid size so we make sure we always space by GAP or
2421 /* Figure out if this row has room. If not, start a new row */
2422 if (GAP
+ element
->BoundingBox
.X2
+ dx
> PCB
->MaxWidth
)
2428 /* figure out how much to move the element */
2429 dx
= minx
- element
->BoundingBox
.X1
;
2430 dy
= miny
- element
->BoundingBox
.Y1
;
2432 /* snap to the grid */
2433 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2435 dy
-= (element
->MarkY
+ dy
) % PCB
->Grid
;
2438 /* move the element */
2439 MoveElementLowLevel (PCB
->Data
, element
, dx
, dy
);
2441 /* and add to the undo list so we can undo this operation */
2442 AddObjectToMoveUndoList (ELEMENT_TYPE
, NULL
, NULL
, element
, dx
, dy
);
2444 /* keep track of how tall this row is */
2445 minx
+= element
->BoundingBox
.X2
- element
->BoundingBox
.X1
+ GAP
;
2446 if (maxy
< element
->BoundingBox
.Y2
)
2448 maxy
= element
->BoundingBox
.Y2
;
2455 /* done with our action so increment the undo # */
2456 IncrementUndoSerialNumber ();
2459 SetChangedFlag (true);
2466 /* --------------------------------------------------------------------------- */
2468 static const char display_syntax
[] =
2469 N_("Display(NameOnPCB|Description|Value)\n"
2470 "Display(Grid|Redraw)\n"
2471 "Display(CycleClip|CycleCrosshair|Toggle45Degree|ToggleStartDirection)\n"
2472 "Display(ToggleGrid|ToggleRubberBandMode|ToggleUniqueNames)\n"
2473 "Display(ToggleMask|ToggleName|ToggleClearLine|ToggleFullPoly|ToggleSnapPin)\n"
2474 "Display(ToggleThindraw|ToggleThindrawPoly|ToggleOrthoMove|ToggleLocalRef)\n"
2475 "Display(ToggleCheckPlanes|ToggleShowDRC|ToggleAutoDRC)\n"
2476 "Display(ToggleLiveRoute|LockNames|OnlyNames)\n"
2477 "Display(Pinout|PinOrPadName)");
2479 static const char display_help
[] = N_("Several display-related actions.");
2481 /* %start-doc actions Display
2488 Specify whether all elements show their name, description, or value.
2491 Redraw the whole board.
2493 @item Toggle45Degree
2494 When clear, lines can be drawn at any angle. When set, lines are
2495 restricted to multiples of 45 degrees and requested lines may be
2496 broken up according to the clip setting.
2499 Changes the way lines are restricted to 45 degree increments. The
2500 various settings are: straight only, orthogonal then angled, and angled
2501 then orthogonal. If AllDirections is set, this action disables it.
2503 @item CycleCrosshair
2504 Changes crosshair drawing. Crosshair may accept form of 4-ray,
2505 8-ray and 12-ray cross.
2507 @item ToggleRubberBandMode
2508 If set, moving an object moves all the lines attached to it too.
2510 @item ToggleStartDirection
2511 If set, each time you set a point in a line, the Clip toggles between
2512 orth-angle and angle-ortho.
2514 @item ToggleUniqueNames
2515 If set, you will not be permitted to change the name of an element to
2516 match that of another element.
2519 If set, pin centers and pad end points are treated as additional grid
2520 points that the cursor can snap to.
2522 @item ToggleLocalRef
2523 If set, the mark is automatically set to the beginning of any move, so
2524 you can see the relative distance you've moved.
2526 @item ToggleThindraw
2527 If set, objects on the screen are drawn as outlines (lines are drawn
2528 as center-lines). This lets you see line endpoints hidden under pins,
2531 @item ToggleThindrawPoly
2532 If set, polygons on the screen are drawn as outlines.
2535 If set, pending objects (i.e. lines you're in the process of drawing)
2536 will be drawn with an outline showing how far away from other copper
2539 @item ToggleLiveRoute
2540 If set, the progress of the autorouter will be visible on the screen.
2543 If set, you will not be permitted to make connections which violate
2544 the current DRC and netlist settings.
2546 @item ToggleCheckPlanes
2547 If set, lines and arcs aren't drawn, which usually leaves just the
2548 polygons. If you also disable all but the layer you're interested in,
2549 this allows you to check for isolated regions.
2551 @item ToggleOrthoMove
2552 If set, the crosshair is only allowed to move orthogonally from its
2553 previous position. I.e. you can move an element or line up, down,
2554 left, or right, but not up+left or down+right.
2557 Selects whether the pinouts show the pin names or the pin numbers.
2559 @item ToggleLockNames
2560 If set, text will ignore left mouse clicks and actions that work on
2561 objects under the mouse. You can still select text with a lasso (left
2562 mouse drag) and perform actions on the selection.
2564 @item ToggleOnlyNames
2565 If set, only text will be sensitive for mouse clicks and actions that
2566 work on objects under the mouse. You can still select other objects
2567 with a lasso (left mouse drag) and perform actions on the selection.
2570 Turns the solder mask on or off.
2572 @item ToggleClearLine
2573 When set, the clear-line flag causes new lines and arcs to have their
2574 ``clear polygons'' flag set, so they won't be electrically connected
2575 to any polygons they overlap.
2577 @item ToggleFullPoly
2578 When set, the full-poly flag causes new polygons to have their
2579 ``full polygon'' flag set, so all parts of them will be displayed
2580 instead of only the biggest one.
2583 Resets the origin of the current grid to be wherever the mouse pointer
2584 is (not where the crosshair currently is). If you provide two numbers
2585 after this, the origin is set to that coordinate.
2588 Toggles whether the grid is displayed or not.
2591 Causes the pinout of the element indicated by the cursor to be
2592 displayed, usually in a separate window.
2595 Toggles whether the names of pins, pads, or (yes) vias will be
2596 displayed. If the cursor is over an element, all of its pins and pads
2603 static enum crosshair_shape
2604 CrosshairShapeIncrement (enum crosshair_shape shape
)
2608 case Basic_Crosshair_Shape
:
2609 shape
= Union_Jack_Crosshair_Shape
;
2611 case Union_Jack_Crosshair_Shape
:
2612 shape
= Dozen_Crosshair_Shape
;
2614 case Dozen_Crosshair_Shape
:
2615 shape
= Crosshair_Shapes_Number
;
2617 case Crosshair_Shapes_Number
:
2618 shape
= Basic_Crosshair_Shape
;
2625 ActionDisplay (int argc
, char **argv
, Coord childX
, Coord childY
)
2627 char *function
, *str_dir
;
2634 if (function
&& (!str_dir
|| !*str_dir
))
2636 switch (id
= GetFunctionID (function
))
2640 case F_ClearAndRedraw
:
2645 /* change the displayed name of elements */
2649 ELEMENT_LOOP (PCB
->Data
);
2651 EraseElementName (element
);
2654 CLEAR_FLAG (DESCRIPTIONFLAG
| NAMEONPCBFLAG
, PCB
);
2660 SET_FLAG (NAMEONPCBFLAG
, PCB
);
2663 SET_FLAG (DESCRIPTIONFLAG
, PCB
);
2666 ELEMENT_LOOP (PCB
->Data
);
2668 DrawElementName (element
);
2674 /* toggle line-adjust flag */
2675 case F_ToggleAllDirections
:
2676 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2677 AdjustAttachedObjects ();
2681 notify_crosshair_change (false);
2682 if (TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
2684 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2688 PCB
->Clipping
= (PCB
->Clipping
+ 1) % 3;
2689 AdjustAttachedObjects ();
2690 notify_crosshair_change (true);
2693 case F_CycleCrosshair
:
2694 notify_crosshair_change (false);
2695 Crosshair
.shape
= CrosshairShapeIncrement(Crosshair
.shape
);
2696 if (Crosshair_Shapes_Number
== Crosshair
.shape
)
2697 Crosshair
.shape
= Basic_Crosshair_Shape
;
2698 notify_crosshair_change (true);
2701 case F_ToggleRubberBandMode
:
2702 notify_crosshair_change (false);
2703 TOGGLE_FLAG (RUBBERBANDFLAG
, PCB
);
2704 notify_crosshair_change (true);
2707 case F_ToggleStartDirection
:
2708 notify_crosshair_change (false);
2709 TOGGLE_FLAG (SWAPSTARTDIRFLAG
, PCB
);
2710 notify_crosshair_change (true);
2713 case F_ToggleUniqueNames
:
2714 TOGGLE_FLAG (UNIQUENAMEFLAG
, PCB
);
2717 case F_ToggleSnapPin
:
2718 notify_crosshair_change (false);
2719 TOGGLE_FLAG (SNAPPINFLAG
, PCB
);
2720 notify_crosshair_change (true);
2723 case F_ToggleLocalRef
:
2724 TOGGLE_FLAG (LOCALREFFLAG
, PCB
);
2727 case F_ToggleThindraw
:
2728 TOGGLE_FLAG (THINDRAWFLAG
, PCB
);
2732 case F_ToggleThindrawPoly
:
2733 TOGGLE_FLAG (THINDRAWPOLYFLAG
, PCB
);
2737 case F_ToggleLockNames
:
2738 TOGGLE_FLAG (LOCKNAMESFLAG
, PCB
);
2739 CLEAR_FLAG (ONLYNAMESFLAG
, PCB
);
2742 case F_ToggleOnlyNames
:
2743 TOGGLE_FLAG (ONLYNAMESFLAG
, PCB
);
2744 CLEAR_FLAG (LOCKNAMESFLAG
, PCB
);
2747 case F_ToggleHideNames
:
2748 TOGGLE_FLAG (HIDENAMESFLAG
, PCB
);
2752 case F_ToggleShowDRC
:
2753 TOGGLE_FLAG (SHOWDRCFLAG
, PCB
);
2756 case F_ToggleLiveRoute
:
2757 TOGGLE_FLAG (LIVEROUTEFLAG
, PCB
);
2760 case F_ToggleAutoDRC
:
2761 notify_crosshair_change (false);
2762 TOGGLE_FLAG (AUTODRCFLAG
, PCB
);
2763 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
2765 if (ClearFlagOnAllObjects (true, CONNECTEDFLAG
| FOUNDFLAG
))
2767 IncrementUndoSerialNumber ();
2770 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
2772 LookupConnection (Crosshair
.AttachedLine
.Point1
.X
,
2773 Crosshair
.AttachedLine
.Point1
.Y
,
2774 true, 1, CONNECTEDFLAG
, false);
2775 LookupConnection (Crosshair
.AttachedLine
.Point1
.X
,
2776 Crosshair
.AttachedLine
.Point1
.Y
,
2777 true, 1, FOUNDFLAG
, true);
2780 notify_crosshair_change (true);
2783 case F_ToggleCheckPlanes
:
2784 TOGGLE_FLAG (CHECKPLANESFLAG
, PCB
);
2788 case F_ToggleOrthoMove
:
2789 TOGGLE_FLAG (ORTHOMOVEFLAG
, PCB
);
2793 TOGGLE_FLAG (SHOWNUMBERFLAG
, PCB
);
2798 TOGGLE_FLAG (SHOWMASKFLAG
, PCB
);
2802 case F_ToggleClearLine
:
2803 TOGGLE_FLAG (CLEARNEWFLAG
, PCB
);
2806 case F_ToggleFullPoly
:
2807 TOGGLE_FLAG (NEWFULLPOLYFLAG
, PCB
);
2810 /* shift grid alignment */
2813 Coord oldGrid
= PCB
->Grid
;
2816 if (MoveCrosshairAbsolute (Crosshair
.X
, Crosshair
.Y
))
2817 notify_crosshair_change (true); /* first notify was in MoveCrosshairAbs */
2818 SetGrid (oldGrid
, true);
2822 /* toggle displaying of the grid */
2824 Settings
.DrawGrid
= !Settings
.DrawGrid
;
2828 /* display the pinout of an element */
2831 ElementType
*element
;
2835 gui
->get_coords (_("Click on an element"), &x
, &y
);
2837 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
2838 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
2840 element
= (ElementType
*) ptrtmp
;
2841 gui
->show_item (element
);
2846 /* toggle displaying of pin/pad/via names */
2847 case F_PinOrPadName
:
2849 void *ptr1
, *ptr2
, *ptr3
;
2851 switch (SearchScreen (Crosshair
.X
, Crosshair
.Y
,
2852 ELEMENT_TYPE
| PIN_TYPE
| PAD_TYPE
|
2853 VIA_TYPE
, (void **) &ptr1
, (void **) &ptr2
,
2857 PIN_LOOP ((ElementType
*) ptr1
);
2859 if (TEST_FLAG (DISPLAYNAMEFLAG
, pin
))
2863 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, pin
, pin
);
2864 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pin
);
2867 PAD_LOOP ((ElementType
*) ptr1
);
2869 if (TEST_FLAG (DISPLAYNAMEFLAG
, pad
))
2873 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, pad
, pad
);
2874 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pad
);
2877 SetChangedFlag (true);
2878 IncrementUndoSerialNumber ();
2883 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
))
2884 ErasePinName ((PinType
*) ptr2
);
2886 DrawPinName ((PinType
*) ptr2
);
2887 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, ptr2
, ptr3
);
2888 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
);
2889 SetChangedFlag (true);
2890 IncrementUndoSerialNumber ();
2895 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PadType
*) ptr2
))
2896 ErasePadName ((PadType
*) ptr2
);
2898 DrawPadName ((PadType
*) ptr2
);
2899 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, ptr2
, ptr3
);
2900 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PadType
*) ptr2
);
2901 SetChangedFlag (true);
2902 IncrementUndoSerialNumber ();
2906 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
))
2907 EraseViaName ((PinType
*) ptr2
);
2909 DrawViaName ((PinType
*) ptr2
);
2910 AddObjectToFlagUndoList (VIA_TYPE
, ptr1
, ptr2
, ptr3
);
2911 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
);
2912 SetChangedFlag (true);
2913 IncrementUndoSerialNumber ();
2923 else if (function
&& str_dir
)
2925 switch (GetFunctionID (function
))
2930 PCB
->GridOffsetX
= GetValue (argv
[1], NULL
, NULL
);
2931 PCB
->GridOffsetY
= GetValue (argv
[2], NULL
, NULL
);
2932 if (Settings
.DrawGrid
)
2949 /* --------------------------------------------------------------------------- */
2951 static const char mode_syntax
[] =
2952 N_("Mode(Arc|Arrow|Copy|InsertPoint|Line|Lock|Move|None|PasteBuffer)\n"
2953 "Mode(Polygon|Rectangle|Remove|Rotate|Text|Thermal|Via)\n"
2954 "Mode(Notify|Release|Cancel|Stroke)\n"
2955 "Mode(Save|Restore)");
2957 static const char mode_help
[] = N_("Change or use the tool mode.");
2959 /* %start-doc actions Mode
2979 Select the indicated tool.
2982 Called when you press the mouse button, or move the mouse.
2985 Called when you release the mouse button.
2988 Cancels any pending tool activity, allowing you to restart elsewhere.
2989 For example, this allows you to start a new line rather than attach a
2990 line to the previous line.
2993 Similar to Cancel but calling this action a second time will return
2997 If your @code{pcb} was built with libstroke, this invokes the stroke
2998 input method. If not, this will restart a drawing mode if you were
2999 drawing, else it will select objects.
3002 Remembers the current tool.
3005 Restores the tool to the last saved tool.
3012 ActionMode (int argc
, char **argv
, Coord x
, Coord y
)
3014 char *function
= ARG (0);
3018 Note
.X
= Crosshair
.X
;
3019 Note
.Y
= Crosshair
.Y
;
3020 notify_crosshair_change (false);
3021 switch (GetFunctionID (function
))
3027 SetMode (ARROW_MODE
);
3030 SetMode (COPY_MODE
);
3033 SetMode (INSERTPOINT_MODE
);
3036 SetMode (LINE_MODE
);
3039 SetMode (LOCK_MODE
);
3042 SetMode (MOVE_MODE
);
3049 int saved_mode
= Settings
.Mode
;
3051 SetMode (saved_mode
);
3056 switch (Settings
.Mode
)
3059 case PASTEBUFFER_MODE
:
3065 case INSERTPOINT_MODE
:
3066 case RUBBERBANDMOVE_MODE
:
3070 SetMode (ARROW_MODE
);
3074 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3075 SetMode (ARROW_MODE
);
3079 SetMode (LINE_MODE
);
3083 case RECTANGLE_MODE
:
3084 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3085 SetMode (ARROW_MODE
);
3089 SetMode (RECTANGLE_MODE
);
3094 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3095 SetMode (ARROW_MODE
);
3099 SetMode (POLYGON_MODE
);
3103 case POLYGONHOLE_MODE
:
3104 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3105 SetMode (ARROW_MODE
);
3109 SetMode (POLYGONHOLE_MODE
);
3114 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3115 SetMode (ARROW_MODE
);
3136 SetMode (PASTEBUFFER_MODE
);
3139 SetMode (POLYGON_MODE
);
3142 SetMode (POLYGONHOLE_MODE
);
3144 #ifndef HAVE_LIBSTROKE
3157 SetMode (REMOVE_MODE
);
3160 SetMode (RECTANGLE_MODE
);
3163 SetMode (ROTATE_MODE
);
3166 #ifdef HAVE_LIBSTROKE
3168 StrokeBox
.X1
= Crosshair
.X
;
3169 StrokeBox
.Y1
= Crosshair
.Y
;
3172 /* Handle middle mouse button restarts of drawing mode. If not in
3173 | a drawing mode, middle mouse button will select objects.
3175 if (Settings
.Mode
== LINE_MODE
3176 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3178 SetMode (LINE_MODE
);
3180 else if (Settings
.Mode
== ARC_MODE
3181 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3183 else if (Settings
.Mode
== RECTANGLE_MODE
3184 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3185 SetMode (RECTANGLE_MODE
);
3186 else if (Settings
.Mode
== POLYGON_MODE
3187 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3188 SetMode (POLYGON_MODE
);
3193 SetMode (ARROW_MODE
);
3199 SetMode (TEXT_MODE
);
3202 SetMode (THERMAL_MODE
);
3208 case F_Restore
: /* restore the last saved mode */
3212 case F_Save
: /* save currently selected mode */
3216 notify_crosshair_change (true);
3223 /* --------------------------------------------------------------------------- */
3225 static const char removeselected_syntax
[] = N_("RemoveSelected()");
3227 static const char removeselected_help
[] = N_("Removes any selected objects.");
3229 /* %start-doc actions RemoveSelected
3234 ActionRemoveSelected (int argc
, char **argv
, Coord x
, Coord y
)
3236 if (RemoveSelected ())
3237 SetChangedFlag (true);
3241 /* --------------------------------------------------------------------------- */
3243 static const char renumber_syntax
[] = N_("Renumber()\n"
3244 "Renumber(filename)");
3246 static const char renumber_help
[] =
3247 N_("Renumber all elements. The changes will be recorded to filename\n"
3248 "for use in backannotating these changes to the schematic.");
3250 /* %start-doc actions Renumber
3255 ActionRenumber (int argc
, char **argv
, Coord x
, Coord y
)
3257 bool changed
= false;
3258 ElementType
**element_list
;
3259 ElementType
**locked_element_list
;
3260 unsigned int i
, j
, k
, cnt
, lock_cnt
;
3266 static char * default_file
= NULL
;
3267 size_t cnt_list_sz
= 100;
3273 char **was
, **is
, *pin
;
3274 unsigned int c_cnt
= 0;
3281 * We deal with the case where name already exists in this
3282 * function so the GUI doesn't need to deal with it
3284 name
= gui
->fileselect (_("Save Renumber Annotation File As ..."),
3285 _("Choose a file to record the renumbering to.\n"
3286 "This file may be used to back annotate the\n"
3287 "change to the schematics.\n"),
3288 default_file
, ".eco", "eco",
3298 free (default_file
);
3299 default_file
= NULL
;
3304 default_file
= strdup (name
);
3307 if ((out
= fopen (name
, "r")))
3310 if (!gui
->confirm_dialog (_("File exists! Ok to overwrite?"), 0))
3312 if (free_name
&& name
)
3318 if ((out
= fopen (name
, "w")) == NULL
)
3320 Message (_("Could not open %s\n"), name
);
3321 if (free_name
&& name
)
3326 if (free_name
&& name
)
3329 fprintf (out
, "*COMMENT* PCB Annotation File\n");
3330 fprintf (out
, "*FILEVERSION* 20061031\n");
3333 * Make a first pass through all of the elements and sort them out
3334 * by location on the board. While here we also collect a list of
3337 * We'll actually renumber things in the 2nd pass.
3339 element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementType
*));
3340 locked_element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementType
*));
3341 was
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3342 is
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3343 if (element_list
== NULL
|| locked_element_list
== NULL
|| was
== NULL
3346 fprintf (stderr
, "calloc() failed in %s\n", __FUNCTION__
);
3353 ELEMENT_LOOP (PCB
->Data
);
3355 if (TEST_FLAG (LOCKFLAG
, element
->Name
) || TEST_FLAG (LOCKFLAG
, element
))
3358 * add to the list of locked elements which we won't try to
3359 * renumber and whose reference designators are now reserved.
3362 "*WARN* Element \"%s\" at %$md is locked and will not be renumbered.\n",
3363 UNKNOWN (NAMEONPCB_NAME (element
)), element
->MarkX
, element
->MarkY
);
3364 locked_element_list
[lock_cnt
] = element
;
3370 /* count of devices which will be renumbered */
3373 /* search for correct position in the list */
3375 while (element_list
[i
] && element
->MarkY
> element_list
[i
]->MarkY
)
3379 * We have found the position where we have the first element that
3380 * has the same Y value or a lower Y value. Now move forward if
3381 * needed through the X values
3383 while (element_list
[i
]
3384 && element
->MarkY
== element_list
[i
]->MarkY
3385 && element
->MarkX
> element_list
[i
]->MarkX
)
3388 for (j
= cnt
- 1; j
> i
; j
--)
3390 element_list
[j
] = element_list
[j
- 1];
3392 element_list
[i
] = element
;
3399 * Now that the elements are sorted by board position, we go through
3400 * and renumber them.
3404 * turn off the flag which requires unique names so it doesn't get
3405 * in our way. When we're done with the renumber we will have unique
3408 unique
= TEST_FLAG (UNIQUENAMEFLAG
, PCB
);
3409 CLEAR_FLAG (UNIQUENAMEFLAG
, PCB
);
3411 cnt_list
= (struct _cnt_list
*)calloc (cnt_list_sz
, sizeof (struct _cnt_list
));
3412 for (i
= 0; i
< cnt
; i
++)
3414 /* If there is no refdes, maybe just spit out a warning */
3415 if (NAMEONPCB_NAME (element_list
[i
]))
3417 /* figure out the prefix */
3418 tmps
= strdup (NAMEONPCB_NAME (element_list
[i
]));
3420 while (tmps
[j
] && (tmps
[j
] < '0' || tmps
[j
] > '9')
3425 /* check the counter for this prefix */
3427 cnt_list
[j
].name
&& (strcmp (cnt_list
[j
].name
, tmps
) != 0)
3428 && j
< cnt_list_sz
; j
++);
3430 /* grow the list if needed */
3431 if (j
== cnt_list_sz
)
3434 cnt_list
= (struct _cnt_list
*)realloc (cnt_list
, cnt_list_sz
);
3435 if (cnt_list
== NULL
)
3437 fprintf (stderr
, _("realloc failed() in %s\n"), __FUNCTION__
);
3440 /* zero out the memory that we added */
3441 for (tmpi
= j
; tmpi
< cnt_list_sz
; tmpi
++)
3443 cnt_list
[tmpi
].name
= NULL
;
3444 cnt_list
[tmpi
].cnt
= 0;
3449 * start a new counter if we don't have a counter for this
3452 if (!cnt_list
[j
].name
)
3454 cnt_list
[j
].name
= strdup (tmps
);
3455 cnt_list
[j
].cnt
= 0;
3459 * check to see if the new refdes is already used by a
3468 /* space for the prefix plus 1 digit plus the '\0' */
3469 sz
= strlen (cnt_list
[j
].name
) + 2;
3471 /* and 1 more per extra digit needed to hold the number */
3472 tmpi
= cnt_list
[j
].cnt
;
3478 tmps
= (char *)malloc (sz
* sizeof (char));
3479 sprintf (tmps
, "%s%d", cnt_list
[j
].name
, cnt_list
[j
].cnt
);
3482 * now compare to the list of reserved (by locked
3485 for (k
= 0; k
< lock_cnt
; k
++)
3488 (UNKNOWN (NAMEONPCB_NAME (locked_element_list
[k
])),
3499 if (strcmp (tmps
, NAMEONPCB_NAME (element_list
[i
])) != 0)
3501 fprintf (out
, "*RENAME* \"%s\" \"%s\"\n",
3502 NAMEONPCB_NAME (element_list
[i
]), tmps
);
3504 /* add this rename to our table of renames so we can update the netlist */
3505 was
[c_cnt
] = strdup (NAMEONPCB_NAME (element_list
[i
]));
3506 is
[c_cnt
] = strdup (tmps
);
3509 AddObjectToChangeNameUndoList (ELEMENT_TYPE
, NULL
, NULL
,
3511 NAMEONPCB_NAME (element_list
3514 ChangeObjectName (ELEMENT_TYPE
, element_list
[i
], NULL
, NULL
,
3518 /* we don't free tmps in this case because it is used */
3525 pcb_fprintf (out
, "*WARN* Element at %$md has no name.\n",
3526 element_list
[i
]->MarkX
, element_list
[i
]->MarkY
);
3533 /* restore the unique flag setting */
3535 SET_FLAG (UNIQUENAMEFLAG
, PCB
);
3540 /* update the netlist */
3541 AddNetlistLibToUndoList (&(PCB
->NetlistLib
));
3543 /* iterate over each net */
3544 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
3547 /* iterate over each pin on the net */
3548 for (j
= 0; j
< PCB
->NetlistLib
.Menu
[i
].EntryN
; j
++)
3551 /* figure out the pin number part from strings like U3-21 */
3552 tmps
= strdup (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3553 for (k
= 0; tmps
[k
] && tmps
[k
] != '-'; k
++);
3557 /* iterate over the list of changed reference designators */
3558 for (k
= 0; k
< c_cnt
; k
++)
3561 * if the pin needs to change, change it and quit
3562 * searching in the list.
3564 if (strcmp (tmps
, was
[k
]) == 0)
3566 free (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3567 PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
=
3568 (char *)malloc ((strlen (is
[k
]) + strlen (pin
) +
3569 2) * sizeof (char));
3570 sprintf (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
,
3571 "%s-%s", is
[k
], pin
);
3579 for (k
= 0; k
< c_cnt
; k
++)
3586 IncrementUndoSerialNumber ();
3587 SetChangedFlag (true);
3590 free (locked_element_list
);
3591 free (element_list
);
3597 /* --------------------------------------------------------------------------- */
3599 static const char ripup_syntax
[] = N_("RipUp(All|Selected|Element)");
3601 static const char ripup_help
[] =
3602 N_("Ripup auto-routed tracks, or convert an element to parts.");
3604 /* %start-doc actions RipUp
3609 Removes all lines and vias which were created by the autorouter.
3612 Removes all selected lines and vias which were created by the
3616 Converts the element under the cursor to parts (vias and lines). Note
3617 that this uses the highest numbered paste buffer.
3624 ActionRipUp (int argc
, char **argv
, Coord x
, Coord y
)
3626 char *function
= ARG (0);
3627 bool changed
= false;
3631 switch (GetFunctionID (function
))
3634 ALLLINE_LOOP (PCB
->Data
);
3636 if (TEST_FLAG (AUTOFLAG
, line
) && !TEST_FLAG (LOCKFLAG
, line
))
3638 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3643 ALLARC_LOOP (PCB
->Data
);
3645 if (TEST_FLAG (AUTOFLAG
, arc
) && !TEST_FLAG (LOCKFLAG
, arc
))
3647 RemoveObject (ARC_TYPE
, layer
, arc
, arc
);
3652 VIA_LOOP (PCB
->Data
);
3654 if (TEST_FLAG (AUTOFLAG
, via
) && !TEST_FLAG (LOCKFLAG
, via
))
3656 RemoveObject (VIA_TYPE
, via
, via
, via
);
3664 IncrementUndoSerialNumber ();
3665 SetChangedFlag (true);
3669 VISIBLELINE_LOOP (PCB
->Data
);
3671 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, line
)
3672 && !TEST_FLAG (LOCKFLAG
, line
))
3674 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3680 VIA_LOOP (PCB
->Data
);
3682 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, via
)
3683 && !TEST_FLAG (LOCKFLAG
, via
))
3685 RemoveObject (VIA_TYPE
, via
, via
, via
);
3692 IncrementUndoSerialNumber ();
3693 SetChangedFlag (true);
3698 void *ptr1
, *ptr2
, *ptr3
;
3700 if (SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
3701 &ptr1
, &ptr2
, &ptr3
) != NO_TYPE
)
3703 Note
.Buffer
= Settings
.BufferNumber
;
3704 SetBufferNumber (MAX_BUFFER
- 1);
3705 ClearBuffer (PASTEBUFFER
);
3706 CopyObjectToBuffer (PASTEBUFFER
->Data
, PCB
->Data
,
3707 ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3708 SmashBufferElement (PASTEBUFFER
);
3711 SaveUndoSerialNumber ();
3712 EraseObject (ELEMENT_TYPE
, ptr1
, ptr1
);
3713 MoveObjectToRemoveUndoList (ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3714 RestoreUndoSerialNumber ();
3715 CopyPastebufferToLayout (0, 0);
3716 SetBufferNumber (Note
.Buffer
);
3717 SetChangedFlag (true);
3726 /* --------------------------------------------------------------------------- */
3728 static const char addrats_syntax
[] = N_("AddRats(AllRats|SelectedRats|Close)");
3730 static const char addrats_help
[] =
3731 N_("Add one or more rat lines to the board.");
3733 /* %start-doc actions AddRats
3738 Create rat lines for all loaded nets that aren't already connected on
3742 Similarly, but only add rat lines for nets connected to selected pins
3746 Selects the shortest unselected rat on the board.
3753 ActionAddRats (int argc
, char **argv
, Coord x
, Coord y
)
3755 char *function
= ARG (0);
3761 if (Settings
.RatWarn
)
3763 switch (GetFunctionID (function
))
3766 if (AddAllRats (false, NULL
))
3767 SetChangedFlag (true);
3769 case F_SelectedRats
:
3771 if (AddAllRats (true, NULL
))
3772 SetChangedFlag (true);
3775 small
= SQUARE (MAX_COORD
);
3777 RAT_LOOP (PCB
->Data
);
3779 if (TEST_FLAG (SELECTEDFLAG
, line
))
3781 len
= SQUARE (line
->Point1
.X
- line
->Point2
.X
) +
3782 SQUARE (line
->Point1
.Y
- line
->Point2
.Y
);
3792 AddObjectToFlagUndoList (RATLINE_TYPE
, shorty
, shorty
, shorty
);
3793 SET_FLAG (SELECTEDFLAG
, shorty
);
3796 CenterDisplay ((shorty
->Point2
.X
+ shorty
->Point1
.X
) / 2,
3797 (shorty
->Point2
.Y
+ shorty
->Point1
.Y
) / 2);
3805 /* --------------------------------------------------------------------------- */
3807 static const char delete_syntax
[] =
3808 N_("Delete(Object|Selected)\n"
3809 "Delete(AllRats|SelectedRats)");
3811 static const char delete_help
[] = N_("Delete stuff.");
3813 /* %start-doc actions Delete
3818 ActionDelete (int argc
, char **argv
, Coord x
, Coord y
)
3820 char *function
= ARG (0);
3821 int id
= GetFunctionID (function
);
3823 Note
.X
= Crosshair
.X
;
3824 Note
.Y
= Crosshair
.Y
;
3826 if (id
== -1) /* no arg */
3828 if (RemoveSelected() == false)
3836 SetMode(REMOVE_MODE
);
3844 if (DeleteRats (false))
3845 SetChangedFlag (true);
3847 case F_SelectedRats
:
3848 if (DeleteRats (true))
3849 SetChangedFlag (true);
3856 /* --------------------------------------------------------------------------- */
3858 static const char deleterats_syntax
[] =
3859 N_("DeleteRats(AllRats|Selected|SelectedRats)");
3861 static const char deleterats_help
[] = N_("Delete rat lines.");
3863 /* %start-doc actions DeleteRats
3868 ActionDeleteRats (int argc
, char **argv
, Coord x
, Coord y
)
3870 char *function
= ARG (0);
3873 if (Settings
.RatWarn
)
3875 switch (GetFunctionID (function
))
3878 if (DeleteRats (false))
3879 SetChangedFlag (true);
3881 case F_SelectedRats
:
3883 if (DeleteRats (true))
3884 SetChangedFlag (true);
3891 /* --------------------------------------------------------------------------- */
3893 static const char autoplace_syntax
[] = N_("AutoPlaceSelected()");
3895 static const char autoplace_help
[] = N_("Auto-place selected components.");
3897 /* %start-doc actions AutoPlaceSelected
3899 Attempts to re-arrange the selected components such that the nets
3900 connecting them are minimized. Note that you cannot undo this.
3905 ActionAutoPlaceSelected (int argc
, char **argv
, Coord x
, Coord y
)
3908 if (gui
->confirm_dialog (_("Auto-placement can NOT be undone.\n"
3909 "Do you want to continue anyway?\n"), 0))
3911 if (AutoPlaceSelected ())
3912 SetChangedFlag (true);
3917 /* --------------------------------------------------------------------------- */
3919 static const char autoroute_syntax
[] = N_("AutoRoute(AllRats|SelectedRats)");
3921 static const char autoroute_help
[] = N_("Auto-route some or all rat lines.");
3923 /* %start-doc actions AutoRoute
3928 Attempt to autoroute all rats.
3931 Attempt to autoroute the selected rats.
3935 Before autorouting, it's important to set up a few things. First,
3936 make sure any layers you aren't using are disabled, else the
3937 autorouter may use them. Next, make sure the current line and via
3938 styles are set accordingly. Last, make sure "new lines clear
3939 polygons" is set, in case you eventually want to add a copper pour.
3941 Autorouting takes a while. During this time, the program may not be
3947 ActionAutoRoute (int argc
, char **argv
, Coord x
, Coord y
)
3949 char *function
= ARG (0);
3951 if (function
) /* one parameter */
3953 switch (GetFunctionID (function
))
3956 if (AutoRoute (false))
3957 SetChangedFlag (true);
3959 case F_SelectedRats
:
3961 if (AutoRoute (true))
3962 SetChangedFlag (true);
3969 /* --------------------------------------------------------------------------- */
3971 static const char markcrosshair_syntax
[] =
3972 N_("MarkCrosshair()\n"
3973 "MarkCrosshair(Center)");
3975 static const char markcrosshair_help
[] = N_("Set/Reset the Crosshair mark.");
3977 /* %start-doc actions MarkCrosshair
3979 The ``mark'' is a small X-shaped target on the display which is
3980 treated like a second origin (the normal origin is the upper let
3981 corner of the board). The GUI will display a second set of
3982 coordinates for this mark, which tells you how far you are from it.
3984 If no argument is given, the mark is toggled - disabled if it was
3985 enabled, or enabled at the current cursor position of disabled. If
3986 the @code{Center} argument is given, the mark is moved to the current
3992 ActionMarkCrosshair (int argc
, char **argv
, Coord x
, Coord y
)
3994 char *function
= ARG (0);
3995 if (!function
|| !*function
)
3999 notify_mark_change (false);
4000 Marked
.status
= false;
4001 notify_mark_change (true);
4005 notify_mark_change (false);
4006 Marked
.status
= false;
4007 Marked
.status
= true;
4008 Marked
.X
= Crosshair
.X
;
4009 Marked
.Y
= Crosshair
.Y
;
4010 notify_mark_change (true);
4013 else if (GetFunctionID (function
) == F_Center
)
4015 notify_mark_change (false);
4016 Marked
.status
= true;
4017 Marked
.X
= Crosshair
.X
;
4018 Marked
.Y
= Crosshair
.Y
;
4019 notify_mark_change (true);
4024 /* --------------------------------------------------------------------------- */
4026 static const char changesize_syntax
[] =
4027 N_("ChangeSize(Object, delta)\n"
4028 "ChangeSize(SelectedObjects|Selected, delta)\n"
4029 "ChangeSize(SelectedLines|SelectedPins|SelectedVias, delta)\n"
4030 "ChangeSize(SelectedPads|SelectedTexts|SelectedNames, delta)\n"
4031 "ChangeSize(SelectedElements, delta)");
4033 static const char changesize_help
[] = N_("Changes the size of objects.");
4035 /* %start-doc actions ChangeSize
4037 For lines and arcs, this changes the width. For pins and vias, this
4038 changes the overall diameter of the copper annulus. For pads, this
4039 changes the width and, indirectly, the length. For texts and names,
4040 this changes the scaling factor. For elements, this changes the width
4041 of the silk layer lines and arcs for this element.
4046 ActionChangeSize (int argc
, char **argv
, Coord x
, Coord y
)
4048 char *function
= ARG (0);
4049 char *delta
= ARG (1);
4050 char *units
= ARG (2);
4051 bool absolute
; /* indicates if absolute size is given */
4054 if (function
&& delta
)
4056 value
= GetValue (delta
, units
, &absolute
);
4058 value
= delta
[0] == '-' ? -Settings
.increments
->size
4059 : Settings
.increments
->size
;
4060 switch (GetFunctionID (function
))
4065 void *ptr1
, *ptr2
, *ptr3
;
4068 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
4069 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4070 if (TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
4071 Message (_("Sorry, the object is locked\n"));
4072 if (ChangeObjectSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4073 SetChangedFlag (true);
4077 case F_SelectedVias
:
4078 if (ChangeSelectedSize (VIA_TYPE
, value
, absolute
))
4079 SetChangedFlag (true);
4082 case F_SelectedPins
:
4083 if (ChangeSelectedSize (PIN_TYPE
, value
, absolute
))
4084 SetChangedFlag (true);
4087 case F_SelectedPads
:
4088 if (ChangeSelectedSize (PAD_TYPE
, value
, absolute
))
4089 SetChangedFlag (true);
4092 case F_SelectedArcs
:
4093 if (ChangeSelectedSize (ARC_TYPE
, value
, absolute
))
4094 SetChangedFlag (true);
4097 case F_SelectedLines
:
4098 if (ChangeSelectedSize (LINE_TYPE
, value
, absolute
))
4099 SetChangedFlag (true);
4102 case F_SelectedTexts
:
4103 if (ChangeSelectedSize (TEXT_TYPE
, value
, absolute
))
4104 SetChangedFlag (true);
4107 case F_SelectedNames
:
4108 if (ChangeSelectedSize (ELEMENTNAME_TYPE
, value
, absolute
))
4109 SetChangedFlag (true);
4112 case F_SelectedElements
:
4113 if (ChangeSelectedSize (ELEMENT_TYPE
, value
, absolute
))
4114 SetChangedFlag (true);
4118 case F_SelectedObjects
:
4119 if (ChangeSelectedSize (CHANGESIZE_TYPES
, value
, absolute
))
4120 SetChangedFlag (true);
4127 /* --------------------------------------------------------------------------- */
4129 static const char changedrillsize_syntax
[] =
4130 N_("ChangeDrillSize(Object, delta)\n"
4131 "ChangeDrillSize(SelectedPins|SelectedVias|Selected|SelectedObjects, delta)");
4133 static const char changedrillsize_help
[] =
4134 N_("Changes the drilling hole size of objects.");
4136 /* %start-doc actions ChangeDrillSize
4141 ActionChange2ndSize (int argc
, char **argv
, Coord x
, Coord y
)
4143 char *function
= ARG (0);
4144 char *delta
= ARG (1);
4145 char *units
= ARG (2);
4149 if (function
&& delta
)
4151 value
= GetValue (delta
, units
, &absolute
);
4152 switch (GetFunctionID (function
))
4157 void *ptr1
, *ptr2
, *ptr3
;
4159 gui
->get_coords (_("Select an Object"), &x
, &y
);
4161 SearchScreen (x
, y
, CHANGE2NDSIZE_TYPES
,
4162 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4163 if (ChangeObject2ndSize
4164 (type
, ptr1
, ptr2
, ptr3
, value
, absolute
, true))
4165 SetChangedFlag (true);
4169 case F_SelectedVias
:
4170 if (ChangeSelected2ndSize (VIA_TYPE
, value
, absolute
))
4171 SetChangedFlag (true);
4174 case F_SelectedPins
:
4175 if (ChangeSelected2ndSize (PIN_TYPE
, value
, absolute
))
4176 SetChangedFlag (true);
4179 case F_SelectedObjects
:
4180 if (ChangeSelected2ndSize (PIN_TYPES
, value
, absolute
))
4181 SetChangedFlag (true);
4188 /* --------------------------------------------------------------------------- */
4190 static const char changeclearsize_syntax
[] =
4191 N_("ChangeClearSize(Object, delta)\n"
4192 "ChangeClearSize(SelectedPins|SelectedPads|SelectedVias, delta)\n"
4193 "ChangeClearSize(SelectedLines|SelectedArcs, delta\n"
4194 "ChangeClearSize(Selected|SelectedObjects, delta)");
4196 static const char changeclearsize_help
[] =
4197 N_("Changes the clearance size of objects.");
4199 /* %start-doc actions ChangeClearSize
4201 If the solder mask is currently showing, this action changes the
4202 solder mask clearance. If the mask is not showing, this action
4203 changes the polygon clearance.
4208 ActionChangeClearSize (int argc
, char **argv
, Coord x
, Coord y
)
4210 char *function
= ARG (0);
4211 char *delta
= ARG (1);
4212 char *units
= ARG (2);
4216 if (function
&& delta
)
4218 value
= 2 * GetValue (delta
, units
, &absolute
);
4220 value
= delta
[0] == '-' ? -Settings
.increments
->clear
4221 : Settings
.increments
->clear
;
4222 switch (GetFunctionID (function
))
4227 void *ptr1
, *ptr2
, *ptr3
;
4229 gui
->get_coords (_("Select an Object"), &x
, &y
);
4232 CHANGECLEARSIZE_TYPES
, &ptr1
, &ptr2
,
4234 if (ChangeObjectClearSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4235 SetChangedFlag (true);
4238 case F_SelectedVias
:
4239 if (ChangeSelectedClearSize (VIA_TYPE
, value
, absolute
))
4240 SetChangedFlag (true);
4242 case F_SelectedPads
:
4243 if (ChangeSelectedClearSize (PAD_TYPE
, value
, absolute
))
4244 SetChangedFlag (true);
4246 case F_SelectedPins
:
4247 if (ChangeSelectedClearSize (PIN_TYPE
, value
, absolute
))
4248 SetChangedFlag (true);
4250 case F_SelectedLines
:
4251 if (ChangeSelectedClearSize (LINE_TYPE
, value
, absolute
))
4252 SetChangedFlag (true);
4254 case F_SelectedArcs
:
4255 if (ChangeSelectedClearSize (ARC_TYPE
, value
, absolute
))
4256 SetChangedFlag (true);
4259 case F_SelectedObjects
:
4260 if (ChangeSelectedClearSize (CHANGECLEARSIZE_TYPES
, value
, absolute
))
4261 SetChangedFlag (true);
4268 /* --------------------------------------------------------------------------- */
4270 static const char minmaskgap_syntax
[] =
4271 N_("MinMaskGap(delta)\n"
4272 "MinMaskGap(Selected, delta)");
4274 static const char minmaskgap_help
[] =
4275 N_("Ensures the mask is a minimum distance from pins and pads.");
4277 /* %start-doc actions MinMaskGap
4279 Checks all specified pins and/or pads, and increases the mask if
4280 needed to ensure a minimum distance between the pin or pad edge and
4286 ActionMinMaskGap (int argc
, char **argv
, Coord x
, Coord y
)
4288 char *function
= ARG (0);
4289 char *delta
= ARG (1);
4290 char *units
= ARG (2);
4297 if (strcasecmp (function
, "Selected") == 0)
4298 flags
= SELECTEDFLAG
;
4305 value
= 2 * GetValue (delta
, units
, &absolute
);
4307 SaveUndoSerialNumber ();
4308 ELEMENT_LOOP (PCB
->Data
);
4312 if (!TEST_FLAGS (flags
, pin
))
4314 if (pin
->Mask
< pin
->Thickness
+ value
)
4316 ChangeObjectMaskSize (PIN_TYPE
, element
, pin
, 0,
4317 pin
->Thickness
+ value
, 1);
4318 RestoreUndoSerialNumber ();
4324 if (!TEST_FLAGS (flags
, pad
))
4326 if (pad
->Mask
< pad
->Thickness
+ value
)
4328 ChangeObjectMaskSize (PAD_TYPE
, element
, pad
, 0,
4329 pad
->Thickness
+ value
, 1);
4330 RestoreUndoSerialNumber ();
4336 VIA_LOOP (PCB
->Data
);
4338 if (!TEST_FLAGS (flags
, via
))
4340 if (via
->Mask
&& via
->Mask
< via
->Thickness
+ value
)
4342 ChangeObjectMaskSize (VIA_TYPE
, via
, 0, 0, via
->Thickness
+ value
, 1);
4343 RestoreUndoSerialNumber ();
4347 RestoreUndoSerialNumber ();
4348 IncrementUndoSerialNumber ();
4352 /* --------------------------------------------------------------------------- */
4354 static const char mincleargap_syntax
[] =
4355 N_("MinClearGap(delta)\n"
4356 "MinClearGap(Selected, delta)");
4358 static const char mincleargap_help
[] =
4359 N_("Ensures that polygons are a minimum distance from objects.");
4361 /* %start-doc actions MinClearGap
4363 Checks all specified objects, and increases the polygon clearance if
4364 needed to ensure a minimum distance between their edges and the
4370 ActionMinClearGap (int argc
, char **argv
, Coord x
, Coord y
)
4372 char *function
= ARG (0);
4373 char *delta
= ARG (1);
4374 char *units
= ARG (2);
4381 if (strcasecmp (function
, "Selected") == 0)
4382 flags
= SELECTEDFLAG
;
4389 value
= 2 * GetValue (delta
, units
, &absolute
);
4391 SaveUndoSerialNumber ();
4392 ELEMENT_LOOP (PCB
->Data
);
4396 if (!TEST_FLAGS (flags
, pin
))
4398 if (pin
->Clearance
< value
)
4400 ChangeObjectClearSize (PIN_TYPE
, element
, pin
, 0,
4402 RestoreUndoSerialNumber ();
4408 if (!TEST_FLAGS (flags
, pad
))
4410 if (pad
->Clearance
< value
)
4412 ChangeObjectClearSize (PAD_TYPE
, element
, pad
, 0,
4414 RestoreUndoSerialNumber ();
4420 VIA_LOOP (PCB
->Data
);
4422 if (!TEST_FLAGS (flags
, via
))
4424 if (via
->Clearance
< value
)
4426 ChangeObjectClearSize (VIA_TYPE
, via
, 0, 0, value
, 1);
4427 RestoreUndoSerialNumber ();
4431 ALLLINE_LOOP (PCB
->Data
);
4433 if (!TEST_FLAGS (flags
, line
))
4435 if (line
->Clearance
< value
)
4437 ChangeObjectClearSize (LINE_TYPE
, layer
, line
, 0, value
, 1);
4438 RestoreUndoSerialNumber ();
4442 ALLARC_LOOP (PCB
->Data
);
4444 if (!TEST_FLAGS (flags
, arc
))
4446 if (arc
->Clearance
< value
)
4448 ChangeObjectClearSize (ARC_TYPE
, layer
, arc
, 0, value
, 1);
4449 RestoreUndoSerialNumber ();
4453 RestoreUndoSerialNumber ();
4454 IncrementUndoSerialNumber ();
4458 /* --------------------------------------------------------------------------- */
4460 static const char changepinname_syntax
[] =
4461 N_("ChangePinName(ElementName,PinNumber,PinName)");
4463 static const char changepinname_help
[] =
4464 N_("Sets the name of a specific pin on a specific element.");
4466 /* %start-doc actions ChangePinName
4468 This can be especially useful for annotating pin names from a
4469 schematic to the layout without requiring knowledge of the pcb file
4473 ChangePinName(U3, 7, VCC)
4479 ActionChangePinName (int argc
, char **argv
, Coord x
, Coord y
)
4482 char *refdes
, *pinnum
, *pinname
;
4486 AFAIL (changepinname
);
4493 ELEMENT_LOOP (PCB
->Data
);
4495 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
4499 if (NSTRCMP (pinnum
, pin
->Number
) == 0)
4501 AddObjectToChangeNameUndoList (PIN_TYPE
, NULL
, NULL
,
4504 * Note: we can't free() pin->Name first because
4505 * it is used in the undo list
4507 pin
->Name
= strdup (pinname
);
4508 SetChangedFlag (true);
4516 if (NSTRCMP (pinnum
, pad
->Number
) == 0)
4518 AddObjectToChangeNameUndoList (PAD_TYPE
, NULL
, NULL
,
4521 * Note: we can't free() pad->Name first because
4522 * it is used in the undo list
4524 pad
->Name
= strdup (pinname
);
4525 SetChangedFlag (true);
4534 * done with our action so increment the undo # if we actually
4540 defer_needs_update
= 1;
4543 IncrementUndoSerialNumber ();
4544 gui
->invalidate_all ();
4551 /* --------------------------------------------------------------------------- */
4553 static const char changename_syntax
[] =
4554 N_("ChangeName(Object)\n"
4555 "ChangeName(Layout|Layer)");
4557 static const char changename_help
[] = N_("Sets the name of objects.");
4559 /* %start-doc actions ChangeName
4564 Changes the name of the element under the cursor.
4567 Changes the name of the layout. This is printed on the fab drawings.
4570 Changes the name of the currently active layer.
4577 ActionChangeName (int argc
, char **argv
, Coord x
, Coord y
)
4579 char *function
= ARG (0);
4584 switch (GetFunctionID (function
))
4586 /* change the name of an object */
4590 void *ptr1
, *ptr2
, *ptr3
;
4592 gui
->get_coords (_("Select an Object"), &x
, &y
);
4594 SearchScreen (x
, y
, CHANGENAME_TYPES
,
4595 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4597 SaveUndoSerialNumber ();
4598 if (QueryInputAndChangeObjectName (type
, ptr1
, ptr2
, ptr3
))
4600 SetChangedFlag (true);
4601 if (type
== ELEMENT_TYPE
)
4603 RubberbandType
*ptr
;
4606 RestoreUndoSerialNumber ();
4607 Crosshair
.AttachedObject
.RubberbandN
= 0;
4608 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
4609 ptr
= Crosshair
.AttachedObject
.Rubberband
;
4610 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
;
4614 EraseRat ((RatType
*) ptr
->Line
);
4615 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
4616 ptr
->Line
, ptr
->Line
,
4619 IncrementUndoSerialNumber ();
4627 /* change the layout's name */
4630 gui
->prompt_for (_("Enter the layout name:"), EMPTY (PCB
->Name
));
4631 /* NB: ChangeLayoutName takes ownership of the passed memory */
4632 if (name
&& ChangeLayoutName (name
))
4633 SetChangedFlag (true);
4636 /* change the name of the active layer */
4638 name
= gui
->prompt_for (_("Enter the layer name:"),
4639 EMPTY (CURRENT
->Name
));
4640 /* NB: ChangeLayerName takes ownership of the passed memory */
4641 if (name
&& ChangeLayerName (CURRENT
, name
))
4642 SetChangedFlag (true);
4650 /* --------------------------------------------------------------------------- */
4652 static const char morphpolygon_syntax
[] = N_("MorphPolygon(Object|Selected)");
4654 static const char morphpolygon_help
[] =
4655 N_("Converts dead polygon islands into separate polygons.");
4657 /* %start-doc actions MorphPolygon
4659 If a polygon is divided into unconnected "islands", you can use
4660 this command to convert the otherwise disappeared islands into
4661 separate polygons. Be sure the cursor is over a portion of the
4662 polygon that remains visible. Very small islands that may flake
4663 off are automatically deleted.
4668 ActionMorphPolygon (int argc
, char **argv
, Coord x
, Coord y
)
4670 char *function
= ARG (0);
4673 switch (GetFunctionID (function
))
4678 void *ptr1
, *ptr2
, *ptr3
;
4680 gui
->get_coords (_("Select an Object"), &x
, &y
);
4681 if ((type
= SearchScreen (x
, y
, POLYGON_TYPE
,
4682 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4684 MorphPolygon ((LayerType
*) ptr1
, (PolygonType
*) ptr3
);
4686 IncrementUndoSerialNumber ();
4691 case F_SelectedObjects
:
4692 ALLPOLYGON_LOOP (PCB
->Data
);
4694 if (TEST_FLAG (SELECTEDFLAG
, polygon
))
4695 MorphPolygon (layer
, polygon
);
4699 IncrementUndoSerialNumber ();
4706 /* --------------------------------------------------------------------------- */
4708 static const char togglehidename_syntax
[] =
4709 N_("ToggleHideName(Object|SelectedElements)");
4711 static const char togglehidename_help
[] =
4712 N_("Toggles the visibility of element names.");
4714 /* %start-doc actions ToggleHideName
4716 If names are hidden you won't see them on the screen and they will not
4717 appear on the silk layer when you print the layout.
4722 ActionToggleHideName (int argc
, char **argv
, Coord x
, Coord y
)
4724 char *function
= ARG (0);
4725 if (function
&& PCB
->ElementOn
)
4727 switch (GetFunctionID (function
))
4732 void *ptr1
, *ptr2
, *ptr3
;
4734 gui
->get_coords (_("Select an Object"), &x
, &y
);
4735 if ((type
= SearchScreen (x
, y
, ELEMENT_TYPE
,
4736 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4738 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr3
);
4739 EraseElementName ((ElementType
*) ptr2
);
4740 TOGGLE_FLAG (HIDENAMEFLAG
, (ElementType
*) ptr2
);
4741 DrawElementName ((ElementType
*) ptr2
);
4743 IncrementUndoSerialNumber ();
4747 case F_SelectedElements
:
4750 bool changed
= false;
4751 ELEMENT_LOOP (PCB
->Data
);
4753 if ((TEST_FLAG (SELECTEDFLAG
, element
) ||
4754 TEST_FLAG (SELECTEDFLAG
,
4755 &NAMEONPCB_TEXT (element
)))
4756 && (FRONT (element
) || PCB
->InvisibleObjectsOn
))
4758 AddObjectToFlagUndoList (ELEMENT_TYPE
, element
,
4760 EraseElementName (element
);
4761 TOGGLE_FLAG (HIDENAMEFLAG
, element
);
4762 DrawElementName (element
);
4770 IncrementUndoSerialNumber ();
4778 /* --------------------------------------------------------------------------- */
4780 static const char changejoin_syntax
[] =
4781 N_("ChangeJoin(ToggleObject|SelectedLines|SelectedArcs|Selected)");
4783 static const char changejoin_help
[] =
4784 N_("Changes the join (clearance through polygons) of objects.");
4786 /* %start-doc actions ChangeJoin
4788 The join flag determines whether a line or arc, drawn to intersect a
4789 polygon, electrically connects to the polygon or not. When joined,
4790 the line/arc is simply drawn over the polygon, making an electrical
4791 connection. When not joined, a gap is drawn between the line and the
4792 polygon, insulating them from each other.
4797 ActionChangeJoin (int argc
, char **argv
, Coord x
, Coord y
)
4799 char *function
= ARG (0);
4802 switch (GetFunctionID (function
))
4804 case F_ToggleObject
:
4808 void *ptr1
, *ptr2
, *ptr3
;
4810 gui
->get_coords (_("Select an Object"), &x
, &y
);
4812 SearchScreen (x
, y
, CHANGEJOIN_TYPES
,
4813 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4814 if (ChangeObjectJoin (type
, ptr1
, ptr2
, ptr3
))
4815 SetChangedFlag (true);
4819 case F_SelectedLines
:
4820 if (ChangeSelectedJoin (LINE_TYPE
))
4821 SetChangedFlag (true);
4824 case F_SelectedArcs
:
4825 if (ChangeSelectedJoin (ARC_TYPE
))
4826 SetChangedFlag (true);
4830 case F_SelectedObjects
:
4831 if (ChangeSelectedJoin (CHANGEJOIN_TYPES
))
4832 SetChangedFlag (true);
4839 /* --------------------------------------------------------------------------- */
4841 static const char changesquare_syntax
[] =
4842 N_("ChangeSquare(ToggleObject)\n"
4843 "ChangeSquare(SelectedElements|SelectedPins)\n"
4844 "ChangeSquare(Selected|SelectedObjects)");
4846 static const char changesquare_help
[] =
4847 N_("Changes the square flag of pins and pads.");
4849 /* %start-doc actions ChangeSquare
4851 Note that @code{Pins} means both pins and pads.
4858 ActionChangeSquare (int argc
, char **argv
, Coord x
, Coord y
)
4860 char *function
= ARG (0);
4863 switch (GetFunctionID (function
))
4865 case F_ToggleObject
:
4869 void *ptr1
, *ptr2
, *ptr3
;
4871 gui
->get_coords (_("Select an Object"), &x
, &y
);
4873 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4874 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4875 if (ChangeObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4876 SetChangedFlag (true);
4880 case F_SelectedElements
:
4881 if (ChangeSelectedSquare (ELEMENT_TYPE
))
4882 SetChangedFlag (true);
4885 case F_SelectedPins
:
4886 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4887 SetChangedFlag (true);
4891 case F_SelectedObjects
:
4892 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4893 SetChangedFlag (true);
4900 /* --------------------------------------------------------------------------- */
4902 static const char setsquare_syntax
[] =
4903 N_("SetSquare(ToggleObject|SelectedElements|SelectedPins)");
4905 static const char setsquare_help
[] = N_("sets the square-flag of objects.");
4907 /* %start-doc actions SetSquare
4909 Note that @code{Pins} means pins and pads.
4916 ActionSetSquare (int argc
, char **argv
, Coord x
, Coord y
)
4918 char *function
= ARG (0);
4919 if (function
&& *function
)
4921 switch (GetFunctionID (function
))
4923 case F_ToggleObject
:
4927 void *ptr1
, *ptr2
, *ptr3
;
4929 gui
->get_coords (_("Select an Object"), &x
, &y
);
4931 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4932 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4933 if (SetObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4934 SetChangedFlag (true);
4938 case F_SelectedElements
:
4939 if (SetSelectedSquare (ELEMENT_TYPE
))
4940 SetChangedFlag (true);
4943 case F_SelectedPins
:
4944 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4945 SetChangedFlag (true);
4949 case F_SelectedObjects
:
4950 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4951 SetChangedFlag (true);
4958 /* --------------------------------------------------------------------------- */
4960 static const char clearsquare_syntax
[] =
4961 N_("ClearSquare(ToggleObject|SelectedElements|SelectedPins)");
4963 static const char clearsquare_help
[] =
4964 N_("Clears the square-flag of pins and pads.");
4966 /* %start-doc actions ClearSquare
4968 Note that @code{Pins} means pins and pads.
4975 ActionClearSquare (int argc
, char **argv
, Coord x
, Coord y
)
4977 char *function
= ARG (0);
4978 if (function
&& *function
)
4980 switch (GetFunctionID (function
))
4982 case F_ToggleObject
:
4986 void *ptr1
, *ptr2
, *ptr3
;
4988 gui
->get_coords (_("Select an Object"), &x
, &y
);
4990 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4991 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4992 if (ClrObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4993 SetChangedFlag (true);
4997 case F_SelectedElements
:
4998 if (ClrSelectedSquare (ELEMENT_TYPE
))
4999 SetChangedFlag (true);
5002 case F_SelectedPins
:
5003 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
5004 SetChangedFlag (true);
5008 case F_SelectedObjects
:
5009 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
5010 SetChangedFlag (true);
5017 /* --------------------------------------------------------------------------- */
5019 static const char changeoctagon_syntax
[] =
5020 N_("ChangeOctagon(Object|ToggleObject|SelectedObjects|Selected)\n"
5021 "ChangeOctagon(SelectedElements|SelectedPins|SelectedVias)");
5023 static const char changeoctagon_help
[] =
5024 N_("Changes the octagon-flag of pins and vias.");
5026 /* %start-doc actions ChangeOctagon
5033 ActionChangeOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5035 char *function
= ARG (0);
5038 switch (GetFunctionID (function
))
5040 case F_ToggleObject
:
5044 void *ptr1
, *ptr2
, *ptr3
;
5046 gui
->get_coords (_("Select an Object"), &x
, &y
);
5048 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5049 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5050 if (ChangeObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5051 SetChangedFlag (true);
5055 case F_SelectedElements
:
5056 if (ChangeSelectedOctagon (ELEMENT_TYPE
))
5057 SetChangedFlag (true);
5060 case F_SelectedPins
:
5061 if (ChangeSelectedOctagon (PIN_TYPE
))
5062 SetChangedFlag (true);
5065 case F_SelectedVias
:
5066 if (ChangeSelectedOctagon (VIA_TYPE
))
5067 SetChangedFlag (true);
5071 case F_SelectedObjects
:
5072 if (ChangeSelectedOctagon (PIN_TYPES
))
5073 SetChangedFlag (true);
5080 /* --------------------------------------------------------------------------- */
5082 static const char setoctagon_syntax
[] =
5083 N_("SetOctagon(Object|ToggleObject|SelectedElements|Selected)");
5085 static const char setoctagon_help
[] = N_("Sets the octagon-flag of objects.");
5087 /* %start-doc actions SetOctagon
5094 ActionSetOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5096 char *function
= ARG (0);
5099 switch (GetFunctionID (function
))
5101 case F_ToggleObject
:
5105 void *ptr1
, *ptr2
, *ptr3
;
5107 gui
->get_coords (_("Select an Object"), &x
, &y
);
5109 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5110 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5111 if (SetObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5112 SetChangedFlag (true);
5116 case F_SelectedElements
:
5117 if (SetSelectedOctagon (ELEMENT_TYPE
))
5118 SetChangedFlag (true);
5121 case F_SelectedPins
:
5122 if (SetSelectedOctagon (PIN_TYPE
))
5123 SetChangedFlag (true);
5126 case F_SelectedVias
:
5127 if (SetSelectedOctagon (VIA_TYPE
))
5128 SetChangedFlag (true);
5132 case F_SelectedObjects
:
5133 if (SetSelectedOctagon (PIN_TYPES
))
5134 SetChangedFlag (true);
5141 /* --------------------------------------------------------------------------- */
5143 static const char clearoctagon_syntax
[] =
5144 N_("ClearOctagon(ToggleObject|Object|SelectedObjects|Selected)\n"
5145 "ClearOctagon(SelectedElements|SelectedPins|SelectedVias)");
5147 static const char clearoctagon_help
[] =
5148 N_("Clears the octagon-flag of pins and vias.");
5150 /* %start-doc actions ClearOctagon
5157 ActionClearOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5159 char *function
= ARG (0);
5162 switch (GetFunctionID (function
))
5164 case F_ToggleObject
:
5168 void *ptr1
, *ptr2
, *ptr3
;
5170 gui
->get_coords (_("Select an Object"), &x
, &y
);
5172 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGEOCTAGON_TYPES
,
5173 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5174 if (ClrObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5175 SetChangedFlag (true);
5179 case F_SelectedElements
:
5180 if (ClrSelectedOctagon (ELEMENT_TYPE
))
5181 SetChangedFlag (true);
5184 case F_SelectedPins
:
5185 if (ClrSelectedOctagon (PIN_TYPE
))
5186 SetChangedFlag (true);
5189 case F_SelectedVias
:
5190 if (ClrSelectedOctagon (VIA_TYPE
))
5191 SetChangedFlag (true);
5195 case F_SelectedObjects
:
5196 if (ClrSelectedOctagon (PIN_TYPES
))
5197 SetChangedFlag (true);
5204 /* --------------------------------------------------------------------------- */
5206 static const char changehold_syntax
[] =
5207 N_("ChangeHole(ToggleObject|Object|SelectedVias|Selected)");
5209 static const char changehold_help
[] = N_("Changes the hole flag of objects.");
5211 /* %start-doc actions ChangeHole
5213 The "hole flag" of a via determines whether the via is a
5214 plated-through hole (not set), or an unplated hole (set).
5219 ActionChangeHole (int argc
, char **argv
, Coord x
, Coord y
)
5221 char *function
= ARG (0);
5224 switch (GetFunctionID (function
))
5226 case F_ToggleObject
:
5230 void *ptr1
, *ptr2
, *ptr3
;
5232 gui
->get_coords (_("Select an Object"), &x
, &y
);
5233 if ((type
= SearchScreen (x
, y
, VIA_TYPE
,
5234 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5235 && ChangeHole ((PinType
*) ptr3
))
5236 IncrementUndoSerialNumber ();
5240 case F_SelectedVias
:
5242 if (ChangeSelectedHole ())
5243 SetChangedFlag (true);
5250 /* --------------------------------------------------------------------------- */
5252 static const char changepaste_syntax
[] =
5253 N_("ChangePaste(ToggleObject|Object|SelectedPads|Selected)");
5255 static const char changepaste_help
[] =
5256 N_("Changes the no paste flag of objects.");
5258 /* %start-doc actions ChangePaste
5260 The "no paste flag" of a pad determines whether the solderpaste
5261 stencil will have an opening for the pad (no set) or if there wil be
5262 no solderpaste on the pad (set). This is used for things such as
5268 ActionChangePaste (int argc
, char **argv
, Coord x
, Coord y
)
5270 char *function
= ARG (0);
5273 switch (GetFunctionID (function
))
5275 case F_ToggleObject
:
5279 void *ptr1
, *ptr2
, *ptr3
;
5281 gui
->get_coords (_("Select an Object"), &x
, &y
);
5282 if ((type
= SearchScreen (x
, y
, PAD_TYPE
,
5283 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5284 && ChangePaste ((PadType
*) ptr3
))
5285 IncrementUndoSerialNumber ();
5289 case F_SelectedPads
:
5291 if (ChangeSelectedPaste ())
5292 SetChangedFlag (true);
5299 /* --------------------------------------------------------------------------- */
5301 static const char select_syntax
[] =
5302 N_("Select(Object|ToggleObject)\n"
5303 "Select(All|Block|Connection)\n"
5304 "Select(ElementByName|ObjectByName|PadByName|PinByName)\n"
5305 "Select(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5306 "Select(TextByName|ViaByName|NetByName)\n"
5307 "Select(TextByName|ViaByName|NetByName, Name)\n"
5310 static const char select_help
[] = N_("Toggles or sets the selection.");
5312 /* %start-doc actions Select
5324 These all rely on having a regular expression parser built into
5325 @code{pcb}. If the name is not specified then the user is prompted
5326 for a pattern, and all objects that match the pattern and are of the
5327 type specified are selected.
5331 Selects the object under the cursor.
5334 Selects all objects in a rectangle indicated by the cursor.
5337 Selects all objects on the board.
5340 Selects all connections with the ``found'' flag set.
5343 Selects all connections with the ``connected'' flag set.
5346 Converts the selected objects to an element. This uses the highest
5347 numbered paste buffer.
5354 ActionSelect (int argc
, char **argv
, Coord x
, Coord y
)
5356 char *function
= ARG (0);
5359 switch (GetFunctionID (function
))
5361 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5363 /* select objects by their names */
5364 case F_ElementByName
:
5365 type
= ELEMENT_TYPE
;
5367 case F_ObjectByName
:
5388 char *pattern
= ARG (1);
5392 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5394 if (SelectObjectByName (type
, pattern
, true))
5395 SetChangedFlag (true);
5396 if (ARG (1) == NULL
)
5401 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5403 /* select a single object */
5404 case F_ToggleObject
:
5406 if (SelectObject ())
5407 SetChangedFlag (true);
5410 /* all objects in block */
5415 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5416 Crosshair
.AttachedBox
.Point2
.X
);
5417 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5418 Crosshair
.AttachedBox
.Point2
.Y
);
5419 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5420 Crosshair
.AttachedBox
.Point2
.X
);
5421 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5422 Crosshair
.AttachedBox
.Point2
.Y
);
5423 notify_crosshair_change (false);
5425 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5426 SelectBlock (&box
, true))
5428 SetChangedFlag (true);
5429 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5431 notify_crosshair_change (true);
5435 /* select all visible objects */
5440 box
.X1
= -MAX_COORD
;
5441 box
.Y1
= -MAX_COORD
;
5444 if (SelectBlock (&box
, true))
5445 SetChangedFlag (true);
5449 /* all logical connections */
5451 if (SelectByFlag (FOUNDFLAG
, true))
5454 IncrementUndoSerialNumber ();
5455 SetChangedFlag (true);
5459 /* all physical connections */
5461 if (SelectByFlag (CONNECTEDFLAG
, true))
5464 IncrementUndoSerialNumber ();
5465 SetChangedFlag (true);
5472 Note
.Buffer
= Settings
.BufferNumber
;
5473 SetBufferNumber (MAX_BUFFER
- 1);
5474 ClearBuffer (PASTEBUFFER
);
5475 gui
->get_coords (_("Select the Element's Mark Location"), &x
, &y
);
5476 x
= GridFit (x
, PCB
->Grid
, PCB
->GridOffsetX
);
5477 y
= GridFit (y
, PCB
->Grid
, PCB
->GridOffsetY
);
5478 AddSelectedToBuffer (PASTEBUFFER
, x
, y
, true);
5479 SaveUndoSerialNumber ();
5481 ConvertBufferToElement (PASTEBUFFER
);
5482 RestoreUndoSerialNumber ();
5483 CopyPastebufferToLayout (x
, y
);
5484 SetBufferNumber (Note
.Buffer
);
5496 /* FLAG(have_regex,FlagHaveRegex,0) */
5498 FlagHaveRegex (int parm
)
5500 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5507 /* --------------------------------------------------------------------------- */
5509 static const char unselect_syntax
[] =
5510 N_("Unselect(All|Block|Connection)\n"
5511 "Unselect(ElementByName|ObjectByName|PadByName|PinByName)\n"
5512 "Unselect(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5513 "Unselect(TextByName|ViaByName)\n"
5514 "Unselect(TextByName|ViaByName, Name)\n");
5516 static const char unselect_help
[] =
5517 N_("Unselects the object at the pointer location or the specified objects.");
5519 /* %start-doc actions Unselect
5524 Unselect all objects.
5527 Unselect all objects in a rectangle given by the cursor.
5530 Unselect all connections with the ``found'' flag set.
5539 These all rely on having a regular expression parser built into
5540 @code{pcb}. If the name is not specified then the user is prompted
5541 for a pattern, and all objects that match the pattern and are of the
5542 type specified are unselected.
5550 ActionUnselect (int argc
, char **argv
, Coord x
, Coord y
)
5552 char *function
= ARG (0);
5555 switch (GetFunctionID (function
))
5557 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5559 /* select objects by their names */
5560 case F_ElementByName
:
5561 type
= ELEMENT_TYPE
;
5563 case F_ObjectByName
:
5584 char *pattern
= ARG (1);
5588 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5590 if (SelectObjectByName (type
, pattern
, false))
5591 SetChangedFlag (true);
5592 if (ARG (1) == NULL
)
5597 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5599 /* all objects in block */
5604 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5605 Crosshair
.AttachedBox
.Point2
.X
);
5606 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5607 Crosshair
.AttachedBox
.Point2
.Y
);
5608 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5609 Crosshair
.AttachedBox
.Point2
.X
);
5610 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5611 Crosshair
.AttachedBox
.Point2
.Y
);
5612 notify_crosshair_change (false);
5614 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5615 SelectBlock (&box
, false))
5617 SetChangedFlag (true);
5618 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5620 notify_crosshair_change (true);
5624 /* unselect all visible objects */
5629 box
.X1
= -MAX_COORD
;
5630 box
.Y1
= -MAX_COORD
;
5633 if (SelectBlock (&box
, false))
5634 SetChangedFlag (true);
5638 /* all logical connections */
5640 if (SelectByFlag (FOUNDFLAG
, false))
5643 IncrementUndoSerialNumber ();
5644 SetChangedFlag (true);
5648 /* all physical connections */
5650 if (SelectByFlag (CONNECTEDFLAG
, false))
5653 IncrementUndoSerialNumber ();
5654 SetChangedFlag (true);
5667 /* --------------------------------------------------------------------------- */
5669 static const char saveto_syntax
[] =
5670 N_("SaveTo(Layout|LayoutAs,filename)\n"
5671 "SaveTo(AllConnections|AllUnusedPins|ElementConnections,filename)\n"
5672 "SaveTo(PasteBuffer,filename)");
5674 static const char saveto_help
[] = N_("Saves data to a file.");
5676 /* %start-doc actions SaveTo
5681 Saves the current layout.
5684 Saves the current layout, and remembers the filename used.
5686 @item AllConnections
5687 Save all connections to a file.
5690 List all unused pins to a file.
5692 @item ElementConnections
5693 Save connections to the element at the cursor to a file.
5696 Save the content of the active Buffer to a file. This is the graphical way to create a footprint.
5703 ActionSaveTo (int argc
, char **argv
, Coord x
, Coord y
)
5711 if (strcasecmp (function
, "Layout") == 0)
5713 if (SavePCB (PCB
->Filename
) == 0)
5714 SetChangedFlag (false);
5721 if (strcasecmp (function
, "LayoutAs") == 0)
5723 if (SavePCB (name
) == 0)
5725 SetChangedFlag (false);
5726 free (PCB
->Filename
);
5727 PCB
->Filename
= strdup (name
);
5728 if (gui
->notify_filename_changed
!= NULL
)
5729 gui
->notify_filename_changed ();
5734 if (strcasecmp (function
, "AllConnections") == 0)
5738 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5740 LookupConnectionsToAllElements (fp
);
5742 SetChangedFlag (true);
5747 if (strcasecmp (function
, "AllUnusedPins") == 0)
5751 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5753 LookupUnusedPins (fp
);
5755 SetChangedFlag (true);
5760 if (strcasecmp (function
, "ElementConnections") == 0)
5762 ElementType
*element
;
5767 if ((SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
5768 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
5770 element
= (ElementType
*) ptrtmp
;
5772 CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5774 LookupElementConnections (element
, fp
);
5776 SetChangedFlag (true);
5782 if (strcasecmp (function
, "PasteBuffer") == 0)
5784 return SaveBufferElements (name
);
5790 /* --------------------------------------------------------------------------- */
5792 static const char savesettings_syntax
[] =
5793 N_("SaveSettings()\n"
5794 "SaveSettings(local)");
5796 static const char savesettings_help
[] = N_("Saves settings.");
5798 /* %start-doc actions SaveSettings
5800 If you pass no arguments, the settings are stored in
5801 @code{$HOME/.pcb/settings}. If you pass the word @code{local} they're
5802 saved in @code{./pcb.settings}.
5807 ActionSaveSettings (int argc
, char **argv
, Coord x
, Coord y
)
5809 int locally
= argc
> 0 ? (strncasecmp (argv
[0], "local", 5) == 0) : 0;
5810 hid_save_settings (locally
);
5814 /* --------------------------------------------------------------------------- */
5816 static const char loadfrom_syntax
[] =
5817 N_("LoadFrom(Layout|LayoutToBuffer|ElementToBuffer|Netlist|Revert,filename)");
5819 static const char loadfrom_help
[] = N_("Load layout data from a file.");
5821 /* %start-doc actions LoadFrom
5823 This action assumes you know what the filename is. The various GUIs
5824 should have a similar @code{Load} action where the filename is
5825 optional, and will provide their own file selection mechanism to let
5826 you choose the file name.
5831 Loads an entire PCB layout, replacing the current one.
5833 @item LayoutToBuffer
5834 Loads an entire PCB layout to the paste buffer.
5836 @item ElementToBuffer
5837 Loads the given element file into the paste buffer. Element files
5838 contain only a single @code{Element} definition, such as the
5839 ``newlib'' library uses.
5842 Loads a new netlist, replacing any current netlist.
5845 Re-loads the current layout from its disk file, reverting any changes
5853 ActionLoadFrom (int argc
, char **argv
, Coord x
, Coord y
)
5864 if (strcasecmp (function
, "ElementToBuffer") == 0)
5866 notify_crosshair_change (false);
5867 if (LoadElementToBuffer (PASTEBUFFER
, name
, true))
5868 SetMode (PASTEBUFFER_MODE
);
5869 notify_crosshair_change (true);
5872 else if (strcasecmp (function
, "LayoutToBuffer") == 0)
5874 notify_crosshair_change (false);
5875 if (LoadLayoutToBuffer (PASTEBUFFER
, name
))
5876 SetMode (PASTEBUFFER_MODE
);
5877 notify_crosshair_change (true);
5880 else if (strcasecmp (function
, "Layout") == 0)
5882 if (!PCB
->Changed
||
5883 gui
->confirm_dialog (_("OK to override layout data?"), 0))
5887 else if (strcasecmp (function
, "Netlist") == 0)
5889 if (PCB
->Netlistname
)
5890 free (PCB
->Netlistname
);
5891 PCB
->Netlistname
= StripWhiteSpaceAndDup (name
);
5892 FreeLibraryMemory (&PCB
->NetlistLib
);
5893 ImportNetlist (PCB
->Netlistname
);
5896 else if (strcasecmp (function
, "Revert") == 0 && PCB
->Filename
5898 || gui
->confirm_dialog (_("OK to override changes?"), 0)))
5906 /* --------------------------------------------------------------------------- */
5908 static const char new_syntax
[] = N_("New([name])");
5910 static const char new_help
[] = N_("Starts a new layout.");
5912 /* %start-doc actions New
5914 If a name is not given, one is prompted for.
5919 ActionNew (int argc
, char **argv
, Coord x
, Coord y
)
5921 char *name
= ARG (0);
5923 if (!PCB
->Changed
|| gui
->confirm_dialog (_("OK to clear layout data?"), 0))
5926 name
= strdup (name
);
5928 name
= gui
->prompt_for (_("Enter the layout name:"), "");
5933 notify_crosshair_change (false);
5934 /* do emergency saving
5935 * clear the old struct and allocate memory for the new one
5937 if (PCB
->Changed
&& Settings
.SaveInTMP
)
5941 PCB
= CreateNewPCB (true);
5942 CreateNewPCBPost (PCB
, 1);
5944 /* setup the new name and reset some values to default */
5948 ResetStackAndVisibility ();
5949 SetCrosshairRange (0, 0, PCB
->MaxWidth
, PCB
->MaxHeight
);
5950 CenterDisplay (PCB
->MaxWidth
/ 2, PCB
->MaxHeight
/ 2);
5953 hid_action ("PCBChanged");
5954 notify_crosshair_change (true);
5960 /* ---------------------------------------------------------------------------
5961 * no operation, just for testing purposes
5962 * syntax: Bell(volume)
5965 ActionBell (char *volume
)
5970 /* --------------------------------------------------------------------------- */
5972 static const char pastebuffer_syntax
[] =
5973 N_("PasteBuffer(AddSelected|Clear|1..MAX_BUFFER)\n"
5974 "PasteBuffer(Rotate, 1..3)\n"
5975 "PasteBuffer(Convert|Save|Restore|Mirror)\n"
5976 "PasteBuffer(ToLayout, X, Y, units)");
5978 static const char pastebuffer_help
[] =
5979 N_("Various operations on the paste buffer.");
5981 /* %start-doc actions PasteBuffer
5983 There are a number of paste buffers; the actual limit is a
5984 compile-time constant @code{MAX_BUFFER} in @file{globalconst.h}. It
5985 is currently @code{5}. One of these is the ``current'' paste buffer,
5986 often referred to as ``the'' paste buffer.
5991 Copies the selected objects to the current paste buffer.
5994 Remove all objects from the current paste buffer.
5997 Convert the current paste buffer to an element. Vias are converted to
5998 pins, lines are converted to pads.
6001 Convert any elements in the paste buffer back to vias and lines.
6004 Flip all objects in the paste buffer vertically (up/down flip). To mirror
6005 horizontally, combine this with rotations.
6008 Rotates the current buffer. The number to pass is 1..3, where 1 means
6009 90 degrees counter clockwise, 2 means 180 degrees, and 3 means 90
6010 degrees clockwise (270 CCW).
6013 Saves any elements in the current buffer to the indicated file.
6016 Pastes any elements in the current buffer to the indicated X, Y
6017 coordinates in the layout. The @code{X} and @code{Y} are treated like
6018 @code{delta} is for many other objects. For each, if it's prefixed by
6019 @code{+} or @code{-}, then that amount is relative to the last
6020 location. Otherwise, it's absolute. Units can be
6021 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
6022 units, currently 1/100 mil.
6026 Selects the given buffer to be the current paste buffer.
6033 ActionPasteBuffer (int argc
, char **argv
, Coord x
, Coord y
)
6035 char *function
= argc
? argv
[0] : (char *)"";
6036 char *sbufnum
= argc
> 1 ? argv
[1] : (char *)"";
6038 static char *default_file
= NULL
;
6041 notify_crosshair_change (false);
6044 switch (GetFunctionID (function
))
6046 /* clear contents of paste buffer */
6048 ClearBuffer (PASTEBUFFER
);
6051 /* copies objects to paste buffer */
6053 AddSelectedToBuffer (PASTEBUFFER
, 0, 0, false);
6056 /* converts buffer contents into an element */
6058 ConvertBufferToElement (PASTEBUFFER
);
6061 /* break up element for editing */
6063 SmashBufferElement (PASTEBUFFER
);
6068 MirrorBuffer (PASTEBUFFER
);
6074 RotateBuffer (PASTEBUFFER
, (BYTE
) atoi (sbufnum
));
6075 SetCrosshairRangeToBuffer ();
6080 if (PASTEBUFFER
->Data
->ElementN
== 0)
6082 Message (_("Buffer has no elements!\n"));
6088 name
= gui
->fileselect (_("Save Paste Buffer As ..."),
6089 _("Choose a file to save the contents of the\n"
6090 "paste buffer to.\n"),
6091 default_file
, ".fp", "footprint",
6096 free (default_file
);
6097 default_file
= NULL
;
6101 default_file
= strdup (name
);
6112 if ((exist
= fopen (name
, "r")))
6116 confirm_dialog (_("File exists! Ok to overwrite?"), 0))
6117 SaveBufferElements (name
);
6120 SaveBufferElements (name
);
6122 if (free_name
&& name
)
6129 static Coord oldx
= 0, oldy
= 0;
6137 else if (argc
== 3 || argc
== 4)
6139 x
= GetValue (ARG (1), ARG (3), &absolute
);
6142 y
= GetValue (ARG (2), ARG (3), &absolute
);
6148 notify_crosshair_change (true);
6149 AFAIL (pastebuffer
);
6154 if (CopyPastebufferToLayout (x
, y
))
6155 SetChangedFlag (true);
6162 int number
= atoi (function
);
6164 /* correct number */
6166 SetBufferNumber (number
- 1);
6171 notify_crosshair_change (true);
6175 /* --------------------------------------------------------------------------- */
6177 static const char undo_syntax
[] = N_("Undo()\n"
6180 static const char undo_help
[] = N_("Undo recent changes.");
6182 /* %start-doc actions Undo
6184 The unlimited undo feature of @code{Pcb} allows you to recover from
6185 most operations that materially affect you work. Calling
6186 @code{Undo()} without any parameter recovers from the last (non-undo)
6187 operation. @code{ClearList} is used to release the allocated
6188 memory. @code{ClearList} is called whenever a new layout is started or
6189 loaded. See also @code{Redo} and @code{Atomic}.
6191 Note that undo groups operations by serial number; changes with the
6192 same serial number will be undone (or redone) as a group. See
6198 ActionUndo (int argc
, char **argv
, Coord x
, Coord y
)
6200 char *function
= ARG (0);
6201 if (!function
|| !*function
)
6203 /* don't allow undo in the middle of an operation */
6204 if (Settings
.Mode
!= POLYGONHOLE_MODE
&&
6205 Crosshair
.AttachedObject
.State
!= STATE_FIRST
)
6207 if (Crosshair
.AttachedBox
.State
!= STATE_FIRST
6208 && Settings
.Mode
!= ARC_MODE
)
6210 /* undo the last operation */
6212 notify_crosshair_change (false);
6213 if ((Settings
.Mode
== POLYGON_MODE
||
6214 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6215 Crosshair
.AttachedPolygon
.PointN
)
6217 GoToPreviousPoint ();
6218 notify_crosshair_change (true);
6221 /* move anchor point if undoing during line creation */
6222 if (Settings
.Mode
== LINE_MODE
)
6224 if (Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6226 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6227 Undo (true); /* undo the connection find */
6228 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
6229 SetLocalRef (0, 0, false);
6230 notify_crosshair_change (true);
6233 if (Crosshair
.AttachedLine
.State
== STATE_THIRD
)
6236 void *ptr1
, *ptr3
, *ptrtmp
;
6238 /* this search is guaranteed to succeed */
6239 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6241 Crosshair
.AttachedLine
.Point1
.X
,
6242 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6243 ptr2
= (LineType
*) ptrtmp
;
6245 /* save both ends of line */
6246 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point1
.X
;
6247 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point1
.Y
;
6248 if ((type
= Undo (true)))
6249 SetChangedFlag (true);
6250 /* check that the undo was of the right type */
6251 if ((type
& UNDO_CREATE
) == 0)
6253 /* wrong undo type, restore anchor points */
6254 Crosshair
.AttachedLine
.Point2
.X
=
6255 Crosshair
.AttachedLine
.Point1
.X
;
6256 Crosshair
.AttachedLine
.Point2
.Y
=
6257 Crosshair
.AttachedLine
.Point1
.Y
;
6258 notify_crosshair_change (true);
6261 /* move to new anchor */
6262 Crosshair
.AttachedLine
.Point1
.X
=
6263 Crosshair
.AttachedLine
.Point2
.X
;
6264 Crosshair
.AttachedLine
.Point1
.Y
=
6265 Crosshair
.AttachedLine
.Point2
.Y
;
6266 /* check if an intermediate point was removed */
6267 if (type
& UNDO_REMOVE
)
6269 /* this search should find the restored line */
6270 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6273 Crosshair
.AttachedLine
.Point2
.X
,
6274 Crosshair
.AttachedLine
.Point2
.Y
, 0);
6275 ptr2
= (LineType
*) ptrtmp
;
6276 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6278 /* undo loses CONNECTEDFLAG and FOUNDFLAG */
6279 SET_FLAG(CONNECTEDFLAG
, ptr2
);
6280 SET_FLAG(FOUNDFLAG
, ptr2
);
6281 DrawLine (CURRENT
, ptr2
);
6283 Crosshair
.AttachedLine
.Point1
.X
=
6284 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point2
.X
;
6285 Crosshair
.AttachedLine
.Point1
.Y
=
6286 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point2
.Y
;
6288 FitCrosshairIntoGrid (Crosshair
.X
, Crosshair
.Y
);
6289 AdjustAttachedObjects ();
6290 if (--addedLines
== 0)
6292 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
6293 lastLayer
= CURRENT
;
6297 /* this search is guaranteed to succeed too */
6298 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6301 Crosshair
.AttachedLine
.Point1
.X
,
6302 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6303 ptr2
= (LineType
*) ptrtmp
;
6304 lastLayer
= (LayerType
*) ptr1
;
6306 notify_crosshair_change (true);
6310 if (Settings
.Mode
== ARC_MODE
)
6312 if (Crosshair
.AttachedBox
.State
== STATE_SECOND
)
6314 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
6315 notify_crosshair_change (true);
6318 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
)
6320 void *ptr1
, *ptr2
, *ptr3
;
6322 /* guaranteed to succeed */
6323 SearchObjectByLocation (ARC_TYPE
, &ptr1
, &ptr2
, &ptr3
,
6324 Crosshair
.AttachedBox
.Point1
.X
,
6325 Crosshair
.AttachedBox
.Point1
.Y
, 0);
6326 bx
= GetArcEnds ((ArcType
*) ptr2
);
6327 Crosshair
.AttachedBox
.Point1
.X
=
6328 Crosshair
.AttachedBox
.Point2
.X
= bx
->X1
;
6329 Crosshair
.AttachedBox
.Point1
.Y
=
6330 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y1
;
6331 AdjustAttachedObjects ();
6332 if (--addedLines
== 0)
6333 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
6336 /* undo the last destructive operation */
6338 SetChangedFlag (true);
6342 switch (GetFunctionID (function
))
6344 /* clear 'undo objects' list */
6346 ClearUndoList (false);
6350 notify_crosshair_change (true);
6354 /* --------------------------------------------------------------------------- */
6356 static const char redo_syntax
[] = N_("Redo()");
6358 static const char redo_help
[] = N_("Redo recent \"undo\" operations.");
6360 /* %start-doc actions Redo
6362 This routine allows you to recover from the last undo command. You
6363 might want to do this if you thought that undo was going to revert
6364 something other than what it actually did (in case you are confused
6365 about which operations are un-doable), or if you have been backing up
6366 through a long undo list and over-shoot your stopping point. Any
6367 change that is made since the undo in question will trim the redo
6368 list. For example if you add ten lines, then undo three of them you
6369 could use redo to put them back, but if you move a line on the board
6370 before performing the redo, you will lose the ability to "redo" the
6371 three "undone" lines.
6376 ActionRedo (int argc
, char **argv
, Coord x
, Coord y
)
6378 if (((Settings
.Mode
== POLYGON_MODE
||
6379 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6380 Crosshair
.AttachedPolygon
.PointN
) ||
6381 Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6383 notify_crosshair_change (false);
6386 SetChangedFlag (true);
6387 if (Settings
.Mode
== LINE_MODE
&&
6388 Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
6390 LineType
*line
= g_list_last (CURRENT
->Line
)->data
;
6391 Crosshair
.AttachedLine
.Point1
.X
=
6392 Crosshair
.AttachedLine
.Point2
.X
= line
->Point2
.X
;
6393 Crosshair
.AttachedLine
.Point1
.Y
=
6394 Crosshair
.AttachedLine
.Point2
.Y
= line
->Point2
.Y
;
6398 notify_crosshair_change (true);
6402 /* --------------------------------------------------------------------------- */
6404 static const char polygon_syntax
[] = N_("Polygon(Close|PreviousPoint)");
6406 static const char polygon_help
[] = N_("Some polygon related stuff.");
6408 /* %start-doc actions Polygon
6410 Polygons need a special action routine to make life easier.
6415 Creates the final segment of the polygon. This may fail if clipping
6416 to 45 degree lines is switched on, in which case a warning is issued.
6419 Resets the newly entered corner to the previous one. The Undo action
6420 will call Polygon(PreviousPoint) when appropriate to do so.
6427 ActionPolygon (int argc
, char **argv
, Coord x
, Coord y
)
6429 char *function
= ARG (0);
6430 if (function
&& Settings
.Mode
== POLYGON_MODE
)
6432 notify_crosshair_change (false);
6433 switch (GetFunctionID (function
))
6435 /* close open polygon if possible */
6440 /* go back to the previous point */
6441 case F_PreviousPoint
:
6442 GoToPreviousPoint ();
6445 notify_crosshair_change (true);
6450 /* --------------------------------------------------------------------------- */
6452 static const char routestyle_syntax
[] = N_("RouteStyle(1|2|3|4)");
6454 static const char routestyle_help
[] =
6455 N_("Copies the indicated routing style into the current sizes.");
6457 /* %start-doc actions RouteStyle
6462 ActionRouteStyle (int argc
, char **argv
, Coord x
, Coord y
)
6464 char *str
= ARG (0);
6465 RouteStyleType
*rts
;
6470 number
= atoi (str
);
6471 if (number
> 0 && number
<= NUM_STYLES
)
6473 rts
= &PCB
->RouteStyle
[number
- 1];
6474 SetLineSize (rts
->Thick
);
6475 SetViaSize (rts
->Diameter
, true);
6476 SetViaDrillingHole (rts
->Hole
, true);
6477 SetKeepawayWidth (rts
->Keepaway
);
6478 hid_action("RouteStylesChanged");
6485 /* --------------------------------------------------------------------------- */
6487 static const char moveobject_syntax
[] = N_("MoveObject(X,Y,dim)");
6489 static const char moveobject_help
[] =
6490 N_("Moves the object under the crosshair.");
6492 /* %start-doc actions MoveObject
6494 The @code{X} and @code{Y} are treated like @code{delta} is for many
6495 other objects. For each, if it's prefixed by @code{+} or @code{-},
6496 then that amount is relative. Otherwise, it's absolute. Units can be
6497 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
6498 units, currently 1/100 mil.
6503 ActionMoveObject (int argc
, char **argv
, Coord x
, Coord y
)
6505 char *x_str
= ARG (0);
6506 char *y_str
= ARG (1);
6507 char *units
= ARG (2);
6509 bool absolute1
, absolute2
;
6510 void *ptr1
, *ptr2
, *ptr3
;
6513 ny
= GetValue (y_str
, units
, &absolute1
);
6514 nx
= GetValue (x_str
, units
, &absolute2
);
6516 type
= SearchScreen (x
, y
, MOVE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6517 if (type
== NO_TYPE
)
6519 Message (_("Nothing found under crosshair\n"));
6526 Crosshair
.AttachedObject
.RubberbandN
= 0;
6527 if (TEST_FLAG (RUBBERBANDFLAG
, PCB
))
6528 LookupRubberbandLines (type
, ptr1
, ptr2
, ptr3
);
6529 if (type
== ELEMENT_TYPE
)
6530 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
6531 MoveObjectAndRubberband (type
, ptr1
, ptr2
, ptr3
, nx
, ny
);
6532 SetChangedFlag (true);
6536 /* --------------------------------------------------------------------------- */
6538 static const char movetocurrentlayer_syntax
[] =
6539 N_("MoveToCurrentLayer(Object|SelectedObjects)");
6541 static const char movetocurrentlayer_help
[] =
6542 N_("Moves objects to the current layer.");
6544 /* %start-doc actions MoveToCurrentLayer
6546 Note that moving an element from a component layer to a solder layer,
6547 or from solder to component, won't automatically flip it. Use the
6548 @code{Flip()} action to do that.
6553 ActionMoveToCurrentLayer (int argc
, char **argv
, Coord x
, Coord y
)
6555 char *function
= ARG (0);
6558 switch (GetFunctionID (function
))
6563 void *ptr1
, *ptr2
, *ptr3
;
6565 gui
->get_coords (_("Select an Object"), &x
, &y
);
6567 SearchScreen (x
, y
, MOVETOLAYER_TYPES
,
6568 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6569 if (MoveObjectToLayer (type
, ptr1
, ptr2
, ptr3
, CURRENT
, false))
6570 SetChangedFlag (true);
6574 case F_SelectedObjects
:
6576 if (MoveSelectedObjectsToLayer (CURRENT
))
6577 SetChangedFlag (true);
6585 static const char setsame_syntax
[] = N_("SetSame()");
6587 static const char setsame_help
[] =
6588 N_("Sets current layer and sizes to match indicated item.");
6590 /* %start-doc actions SetSame
6592 When invoked over any line, arc, polygon, or via, this changes the
6593 current layer to be the layer that item is on, and changes the current
6594 sizes (thickness, keepaway, drill, etc) according to that item.
6599 ActionSetSame (int argc
, char **argv
, Coord x
, Coord y
)
6601 void *ptr1
, *ptr2
, *ptr3
;
6603 LayerType
*layer
= CURRENT
;
6605 type
= SearchScreen (x
, y
, CLONE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6606 /* set layer current and size from line or arc */
6610 notify_crosshair_change (false);
6611 Settings
.LineThickness
= ((LineType
*) ptr2
)->Thickness
;
6612 Settings
.Keepaway
= ((LineType
*) ptr2
)->Clearance
/ 2;
6613 layer
= (LayerType
*) ptr1
;
6614 if (Settings
.Mode
!= LINE_MODE
)
6615 SetMode (LINE_MODE
);
6616 notify_crosshair_change (true);
6617 hid_action ("RouteStylesChanged");
6621 notify_crosshair_change (false);
6622 Settings
.LineThickness
= ((ArcType
*) ptr2
)->Thickness
;
6623 Settings
.Keepaway
= ((ArcType
*) ptr2
)->Clearance
/ 2;
6624 layer
= (LayerType
*) ptr1
;
6625 if (Settings
.Mode
!= ARC_MODE
)
6627 notify_crosshair_change (true);
6628 hid_action ("RouteStylesChanged");
6632 layer
= (LayerType
*) ptr1
;
6636 notify_crosshair_change (false);
6637 Settings
.ViaThickness
= ((PinType
*) ptr2
)->Thickness
;
6638 Settings
.ViaDrillingHole
= ((PinType
*) ptr2
)->DrillingHole
;
6639 Settings
.Keepaway
= ((PinType
*) ptr2
)->Clearance
/ 2;
6640 if (Settings
.Mode
!= VIA_MODE
)
6642 notify_crosshair_change (true);
6643 hid_action ("RouteStylesChanged");
6649 if (layer
!= CURRENT
)
6651 ChangeGroupVisibility (GetLayerNumber (PCB
->Data
, layer
), true, true);
6658 /* --------------------------------------------------------------------------- */
6660 static const char setflag_syntax
[] =
6661 N_("SetFlag(Object|Selected|SelectedObjects, flag)\n"
6662 "SetFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6663 "SetFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6664 "SetFlag(SelectedElements, flag)\n"
6665 "flag = square | octagon | thermal | join");
6667 static const char setflag_help
[] = N_("Sets flags on objects.");
6669 /* %start-doc actions SetFlag
6671 Turns the given flag on, regardless of its previous setting. See
6675 SetFlag(SelectedPins,thermal)
6681 ActionSetFlag (int argc
, char **argv
, Coord x
, Coord y
)
6683 char *function
= ARG (0);
6684 char *flag
= ARG (1);
6685 ChangeFlag (function
, flag
, 1, "SetFlag");
6689 /* --------------------------------------------------------------------------- */
6691 static const char clrflag_syntax
[] =
6692 N_("ClrFlag(Object|Selected|SelectedObjects, flag)\n"
6693 "ClrFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6694 "ClrFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6695 "ClrFlag(SelectedElements, flag)\n"
6696 "flag = square | octagon | thermal | join");
6698 static const char clrflag_help
[] = N_("Clears flags on objects.");
6700 /* %start-doc actions ClrFlag
6702 Turns the given flag off, regardless of its previous setting. See
6706 ClrFlag(SelectedLines,join)
6712 ActionClrFlag (int argc
, char **argv
, Coord x
, Coord y
)
6714 char *function
= ARG (0);
6715 char *flag
= ARG (1);
6716 ChangeFlag (function
, flag
, 0, "ClrFlag");
6720 /* --------------------------------------------------------------------------- */
6722 static const char changeflag_syntax
[] =
6723 N_("ChangeFlag(Object|Selected|SelectedObjects, flag, value)\n"
6724 "ChangeFlag(SelectedLines|SelectedPins|SelectedVias, flag, value)\n"
6725 "ChangeFlag(SelectedPads|SelectedTexts|SelectedNames, flag, value)\n"
6726 "ChangeFlag(SelectedElements, flag, value)\n"
6727 "flag = square | octagon | thermal | join\n"
6730 static const char changeflag_help
[] = N_("Sets or clears flags on objects.");
6732 /* %start-doc actions ChangeFlag
6734 Toggles the given flag on the indicated object(s). The flag may be
6735 one of the flags listed above (square, octagon, thermal, join). The
6736 value may be the number 0 or 1. If the value is 0, the flag is
6737 cleared. If the value is 1, the flag is set.
6742 ActionChangeFlag (int argc
, char **argv
, Coord x
, Coord y
)
6744 char *function
= ARG (0);
6745 char *flag
= ARG (1);
6746 int value
= argc
> 2 ? atoi (argv
[2]) : -1;
6747 if (value
!= 0 && value
!= 1)
6750 ChangeFlag (function
, flag
, value
, "ChangeFlag");
6756 ChangeFlag (char *what
, char *flag_name
, int value
, char *cmd_name
)
6758 bool (*set_object
) (int, void *, void *, void *);
6759 bool (*set_selected
) (int);
6761 if (NSTRCMP (flag_name
, "square") == 0)
6763 set_object
= value
? SetObjectSquare
: ClrObjectSquare
;
6764 set_selected
= value
? SetSelectedSquare
: ClrSelectedSquare
;
6766 else if (NSTRCMP (flag_name
, "octagon") == 0)
6768 set_object
= value
? SetObjectOctagon
: ClrObjectOctagon
;
6769 set_selected
= value
? SetSelectedOctagon
: ClrSelectedOctagon
;
6771 else if (NSTRCMP (flag_name
, "join") == 0)
6773 /* Note: these are backwards, because the flag is "clear" but
6774 the command is "join". */
6775 set_object
= value
? ClrObjectJoin
: SetObjectJoin
;
6776 set_selected
= value
? ClrSelectedJoin
: SetSelectedJoin
;
6780 Message (_("%s(): Flag \"%s\" is not valid\n"), cmd_name
, flag_name
);
6784 switch (GetFunctionID (what
))
6789 void *ptr1
, *ptr2
, *ptr3
;
6792 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
6793 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6794 if (TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
6795 Message (_("Sorry, the object is locked\n"));
6796 if (set_object (type
, ptr1
, ptr2
, ptr3
))
6797 SetChangedFlag (true);
6801 case F_SelectedVias
:
6802 if (set_selected (VIA_TYPE
))
6803 SetChangedFlag (true);
6806 case F_SelectedPins
:
6807 if (set_selected (PIN_TYPE
))
6808 SetChangedFlag (true);
6811 case F_SelectedPads
:
6812 if (set_selected (PAD_TYPE
))
6813 SetChangedFlag (true);
6816 case F_SelectedLines
:
6817 if (set_selected (LINE_TYPE
))
6818 SetChangedFlag (true);
6821 case F_SelectedTexts
:
6822 if (set_selected (TEXT_TYPE
))
6823 SetChangedFlag (true);
6826 case F_SelectedNames
:
6827 if (set_selected (ELEMENTNAME_TYPE
))
6828 SetChangedFlag (true);
6831 case F_SelectedElements
:
6832 if (set_selected (ELEMENT_TYPE
))
6833 SetChangedFlag (true);
6837 case F_SelectedObjects
:
6838 if (set_selected (CHANGESIZE_TYPES
))
6839 SetChangedFlag (true);
6844 /* --------------------------------------------------------------------------- */
6846 static const char executefile_syntax
[] = N_("ExecuteFile(filename)");
6848 static const char executefile_help
[] = N_("Run actions from the given file.");
6850 /* %start-doc actions ExecuteFile
6852 Lines starting with @code{#} are ignored.
6857 ActionExecuteFile (int argc
, char **argv
, Coord x
, Coord y
)
6866 AFAIL (executefile
);
6870 if ((fp
= fopen (fname
, "r")) == NULL
)
6872 fprintf (stderr
, _("Could not open actions file \"%s\".\n"), fname
);
6877 defer_needs_update
= 0;
6878 while (fgets (line
, sizeof (line
), fp
) != NULL
)
6883 /* eat the trailing newline */
6884 while (*sp
&& *sp
!= '\r' && *sp
!= '\n')
6888 /* eat leading spaces and tabs */
6890 while (*sp
&& (*sp
== ' ' || *sp
== '\t'))
6894 * if we have anything left and its not a comment line
6898 if (*sp
&& *sp
!= '#')
6900 /*Message ("%s : line %-3d : \"%s\"\n", fname, n, sp);*/
6901 hid_parse_actions (sp
);
6906 if (defer_needs_update
)
6908 IncrementUndoSerialNumber ();
6909 gui
->invalidate_all ();
6915 /* --------------------------------------------------------------------------- */
6918 ActionPSCalib (int argc
, char **argv
, Coord x
, Coord y
)
6920 HID
*ps
= hid_find_exporter ("ps");
6921 ps
->calibrate (0.0,0.0);
6925 /* --------------------------------------------------------------------------- */
6927 static ElementType
*element_cache
= NULL
;
6929 static ElementType
*
6930 find_element_by_refdes (char *refdes
)
6933 && NAMEONPCB_NAME(element_cache
)
6934 && strcmp (NAMEONPCB_NAME(element_cache
), refdes
) == 0)
6935 return element_cache
;
6937 ELEMENT_LOOP (PCB
->Data
);
6939 if (NAMEONPCB_NAME(element
)
6940 && strcmp (NAMEONPCB_NAME(element
), refdes
) == 0)
6942 element_cache
= element
;
6943 return element_cache
;
6950 static AttributeType
*
6951 lookup_attr (AttributeListType
*list
, const char *name
)
6954 for (i
=0; i
<list
->Number
; i
++)
6955 if (strcmp (list
->List
[i
].name
, name
) == 0)
6956 return & list
->List
[i
];
6961 delete_attr (AttributeListType
*list
, AttributeType
*attr
)
6963 int idx
= attr
- list
->List
;
6964 if (idx
< 0 || idx
>= list
->Number
)
6966 if (list
->Number
- idx
> 1)
6967 memmove (attr
, attr
+1, (list
->Number
- idx
- 1) * sizeof(AttributeType
));
6971 /* ---------------------------------------------------------------- */
6972 static const char elementlist_syntax
[] =
6973 N_("ElementList(Start|Done|Need,<refdes>,<footprint>,<value>)");
6975 static const char elementlist_help
[] =
6976 N_("Adds the given element if it doesn't already exist.");
6978 /* %start-doc actions elementlist
6983 Indicates the start of an element list; call this before any Need
6987 Searches the board for an element with a matching refdes.
6989 If found, the value and footprint are updated.
6991 If not found, a new element is created with the given footprint and value.
6994 Compares the list of elements needed since the most recent
6995 @code{start} with the list of elements actually on the board. Any
6996 elements that weren't listed are selected, so that the user may delete
7003 static int number_of_footprints_not_found
;
7006 parse_layout_attribute_units (char *name
, int def
)
7008 const char *as
= AttributeGet (PCB
, name
);
7011 return GetValue (as
, NULL
, NULL
);
7015 ActionElementList (int argc
, char **argv
, Coord x
, Coord y
)
7017 ElementType
*e
= NULL
;
7018 char *refdes
, *value
, *footprint
, *old
;
7020 char *function
= argv
[0];
7023 printf("Entered ActionElementList, executing function %s\n", function
);
7026 if (strcasecmp (function
, "start") == 0)
7028 ELEMENT_LOOP (PCB
->Data
);
7030 CLEAR_FLAG (FOUNDFLAG
, element
);
7033 element_cache
= NULL
;
7034 number_of_footprints_not_found
= 0;
7038 if (strcasecmp (function
, "done") == 0)
7040 ELEMENT_LOOP (PCB
->Data
);
7042 if (TEST_FLAG (FOUNDFLAG
, element
))
7044 CLEAR_FLAG (FOUNDFLAG
, element
);
7046 else if (! EMPTY_STRING_P (NAMEONPCB_NAME (element
)))
7048 /* Unnamed elements should remain untouched */
7049 SET_FLAG (SELECTEDFLAG
, element
);
7053 if (number_of_footprints_not_found
> 0)
7054 gui
->confirm_dialog (_("Not all requested footprints were found.\n"
7055 "See the message log for details"),
7060 if (strcasecmp (function
, "need") != 0)
7061 AFAIL (elementlist
);
7064 AFAIL (elementlist
);
7073 args
[0] = footprint
;
7078 printf(" ... footprint = %s\n", footprint
);
7079 printf(" ... refdes = %s\n", refdes
);
7080 printf(" ... value = %s\n", value
);
7083 e
= find_element_by_refdes (refdes
);
7090 printf(" ... Footprint not on board, need to add it.\n");
7092 /* Not on board, need to add it. */
7093 if (LoadFootprint(argc
, args
, x
, y
))
7095 number_of_footprints_not_found
++;
7099 nx
= PCB
->MaxWidth
/ 2;
7100 ny
= PCB
->MaxHeight
/ 2;
7101 d
= MIN (PCB
->MaxWidth
, PCB
->MaxHeight
) / 10;
7103 nx
= parse_layout_attribute_units ("import::newX", nx
);
7104 ny
= parse_layout_attribute_units ("import::newY", ny
);
7105 d
= parse_layout_attribute_units ("import::disperse", d
);
7109 nx
+= rand () % (d
*2) - d
;
7110 ny
+= rand () % (d
*2) - d
;
7115 if (nx
>= PCB
->MaxWidth
)
7116 nx
= PCB
->MaxWidth
- 1;
7119 if (ny
>= PCB
->MaxHeight
)
7120 ny
= PCB
->MaxHeight
- 1;
7122 /* Place components onto center of board. */
7123 if (CopyPastebufferToLayout (nx
, ny
))
7124 SetChangedFlag (true);
7127 else if (e
&& DESCRIPTION_NAME(e
) && strcmp (DESCRIPTION_NAME(e
), footprint
) != 0)
7130 printf(" ... Footprint on board, but different from footprint loaded.\n");
7136 /* Different footprint, we need to swap them out. */
7137 if (LoadFootprint(argc
, args
, x
, y
))
7139 number_of_footprints_not_found
++;
7143 er
= ElementOrientation (e
);
7144 pe
= PASTEBUFFER
->Data
->Element
->data
;
7146 MirrorElementCoordinates (PASTEBUFFER
->Data
, pe
, pe
->MarkY
*2 - PCB
->MaxHeight
);
7147 pr
= ElementOrientation (pe
);
7153 RotateElementLowLevel (PASTEBUFFER
->Data
, pe
, pe
->MarkX
, pe
->MarkY
, (er
-pr
+4)%4);
7155 for (i
=0; i
<MAX_ELEMENTNAMES
; i
++)
7157 pe
->Name
[i
].X
= e
->Name
[i
].X
- mx
+ pe
->MarkX
;
7158 pe
->Name
[i
].Y
= e
->Name
[i
].Y
- my
+ pe
->MarkY
;
7159 pe
->Name
[i
].Direction
= e
->Name
[i
].Direction
;
7160 pe
->Name
[i
].Scale
= e
->Name
[i
].Scale
;
7165 if (CopyPastebufferToLayout (mx
, my
))
7166 SetChangedFlag (true);
7169 /* Now reload footprint */
7170 element_cache
= NULL
;
7171 e
= find_element_by_refdes (refdes
);
7173 old
= ChangeElementText (PCB
, PCB
->Data
, e
, NAMEONPCB_INDEX
, strdup (refdes
));
7176 old
= ChangeElementText (PCB
, PCB
->Data
, e
, VALUE_INDEX
, strdup (value
));
7180 SET_FLAG (FOUNDFLAG
, e
);
7183 printf(" ... Leaving ActionElementList.\n");
7189 /* ---------------------------------------------------------------- */
7190 static const char elementsetattr_syntax
[] =
7191 N_("ElementSetAttr(refdes,name[,value])");
7193 static const char elementsetattr_help
[] =
7194 N_("Sets or clears an element-specific attribute.");
7196 /* %start-doc actions elementsetattr
7198 If a value is specified, the named attribute is added (if not already
7199 present) or changed (if it is) to the given value. If the value is
7200 not specified, the given attribute is removed if present.
7205 ActionElementSetAttr (int argc
, char **argv
, Coord x
, Coord y
)
7207 ElementType
*e
= NULL
;
7208 char *refdes
, *name
, *value
;
7209 AttributeType
*attr
;
7213 AFAIL (changepinname
);
7220 ELEMENT_LOOP (PCB
->Data
);
7222 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
7232 Message(_("Cannot change attribute of %s - element not found\n"), refdes
);
7236 attr
= lookup_attr (&e
->Attributes
, name
);
7241 attr
->value
= strdup (value
);
7243 if (attr
&& ! value
)
7245 delete_attr (& e
->Attributes
, attr
);
7249 CreateNewAttribute (& e
->Attributes
, name
, value
);
7255 /* ---------------------------------------------------------------- */
7256 static const char execcommand_syntax
[] = N_("ExecCommand(command)");
7258 static const char execcommand_help
[] = N_("Runs a command.");
7260 /* %start-doc actions execcommand
7262 Runs the given command, which is a system executable.
7267 ActionExecCommand (int argc
, char **argv
, Coord x
, Coord y
)
7273 AFAIL (execcommand
);
7278 if (system (command
))
7283 /* ---------------------------------------------------------------- */
7286 pcb_spawnvp (char **argv
)
7288 #ifdef HAVE__SPAWNVP
7289 int result
= _spawnvp (_P_WAIT
, argv
[0], (const char * const *) argv
);
7300 Message(_("Cannot fork!"));
7306 execvp (argv
[0], argv
);
7319 /* ---------------------------------------------------------------- */
7321 * Creates a new temporary file name. Hopefully the operating system
7322 * provides a mkdtemp() function to securily create a temporary
7323 * directory with mode 0700. If so then that directory is created and
7324 * the returned string is made up of the directory plus the name
7325 * variable. For example:
7327 * tempfile_name_new ("myfile") might return
7328 * "/var/tmp/pcb.123456/myfile".
7330 * If mkdtemp() is not available then 'name' is ignored and the
7331 * insecure tmpnam() function is used.
7333 * Files/names created with tempfile_name_new() should be unlinked
7334 * with tempfile_unlink to make sure the temporary directory is also
7335 * removed when mkdtemp() is used.
7338 tempfile_name_new (char * name
)
7340 char *tmpfile
= NULL
;
7342 char *tmpdir
, *mytmpdir
;
7346 assert ( name
!= NULL
);
7349 #define TEMPLATE "pcb.XXXXXXXX"
7352 tmpdir
= getenv ("TMPDIR");
7354 /* FIXME -- what about win32? */
7355 if (tmpdir
== NULL
) {
7359 mytmpdir
= (char *) malloc (sizeof(char) *
7364 if (mytmpdir
== NULL
) {
7365 fprintf (stderr
, "%s(): malloc failed()\n", __FUNCTION__
);
7370 (void)strcat (mytmpdir
, tmpdir
);
7371 (void)strcat (mytmpdir
, PCB_DIR_SEPARATOR_S
);
7372 (void)strcat (mytmpdir
, TEMPLATE
);
7373 if (mkdtemp (mytmpdir
) == NULL
) {
7374 fprintf (stderr
, "%s(): mkdtemp (\"%s\") failed\n", __FUNCTION__
, mytmpdir
);
7380 len
= strlen (mytmpdir
) + /* the temp directory name */
7381 1 + /* the directory sep. */
7382 strlen (name
) + /* the file name */
7383 1 /* the \0 termination */
7386 tmpfile
= (char *) malloc (sizeof (char) * len
);
7389 (void)strcat (tmpfile
, mytmpdir
);
7390 (void)strcat (tmpfile
, PCB_DIR_SEPARATOR_S
);
7391 (void)strcat (tmpfile
, name
);
7397 * tmpnam() uses a static buffer so strdup() the result right away
7398 * in case someone decides to create multiple temp names.
7400 tmpfile
= strdup (tmpnam (NULL
));
7403 /* Guile doesn't like \ separators */
7405 for (c
= tmpfile
; *c
; c
++)
7415 /* ---------------------------------------------------------------- */
7417 * Unlink a temporary file. If we have mkdtemp() then our temp file
7418 * lives in a temporary directory and we need to remove that directory
7422 tempfile_unlink (char * name
)
7425 /* SDB says: Want to keep old temp files for examiniation when debugging */
7434 /* it is possible that the file was never created so it is OK if the
7437 /* now figure out the directory name to remove */
7438 e
= strlen (name
) - 1;
7439 while (e
> 0 && name
[e
] != PCB_DIR_SEPARATOR_C
) {e
--;}
7441 dname
= strdup (name
);
7445 * at this point, e *should* point to the end of the directory part
7446 * but lets make sure.
7449 rc2
= rmdir (dname
);
7455 fprintf (stderr
, _("%s(): Unable to determine temp directory name from the temp file\n"),
7457 fprintf (stderr
, "%s(): \"%s\"\n",
7458 __FUNCTION__
, name
);
7462 /* name was allocated with malloc */
7467 * FIXME - should also return -1 if the temp file exists and was not
7475 int rc
= unlink (name
);
7478 fprintf (stderr
, _("Failed to unlink \"%s\"\n"), name
);
7489 /* ---------------------------------------------------------------- */
7490 static const char import_syntax
[] =
7492 "Import([gnetlist|make[,source,source,...]])\n"
7493 "Import(setnewpoint[,(mark|center|X,Y)])\n"
7494 "Import(setdisperse,D,units)\n");
7496 static const char import_help
[] = N_("Import schematics.");
7498 /* %start-doc actions Import
7500 Imports element and netlist data from the schematics (or some other
7501 source). The first parameter, which is optional, is the mode. If not
7502 specified, the @code{import::mode} attribute in the PCB is used.
7503 @code{gnetlist} means gnetlist is used to obtain the information from
7504 the schematics. @code{make} invokes @code{make}, assuming the user
7505 has a @code{Makefile} in the current directory. The @code{Makefile}
7506 will be invoked with the following variables set:
7511 The name of the .pcb file
7514 A space-separated list of source files
7517 The name of the file in which to put the command script, which may
7518 contain any @pcb{} actions. By default, this is a temporary file
7519 selected by @pcb{}, but if you specify an @code{import::outfile}
7520 attribute, that file name is used instead (and not automatically
7521 deleted afterwards).
7525 The target specified to be built is the first of these that apply:
7530 The target specified by an @code{import::target} attribute.
7533 The output file specified by an @code{import::outfile} attribute.
7536 If nothing else is specified, the target is @code{pcb_import}.
7540 If you specify an @code{import::makefile} attribute, then "-f <that
7541 file>" will be added to the command line.
7543 If you specify the mode, you may also specify the source files
7544 (schematics). If you do not specify any, the list of schematics is
7545 obtained by reading the @code{import::src@var{N}} attributes (like
7546 @code{import::src0}, @code{import::src1}, etc).
7548 For compatibility with future extensions to the import file format,
7549 the generated file @emph{must not} start with the two characters
7552 If a temporary file is needed the @code{TMPDIR} environment variable
7553 is used to select its location.
7555 Note that the programs @code{gnetlist} and @code{make} may be
7556 overridden by the user via the @code{make-program} and @code{gnetlist}
7557 @code{pcb} settings (i.e. in @code{~/.pcb/settings} or on the command
7560 If @pcb{} cannot determine which schematic(s) to import from, the GUI
7561 is called to let user choose (see @code{ImportGUI()}).
7563 Note that Import() doesn't delete anything - after an Import, elements
7564 which shouldn't be on the board are selected and may be removed once
7565 it's determined that the deletion is appropriate.
7567 If @code{Import()} is called with @code{setnewpoint}, then the location
7568 of new components can be specified. This is where parts show up when
7569 they're added to the board. The default is the center of the board.
7573 @item Import(setnewpoint)
7575 Prompts the user to click on the board somewhere, uses that point. If
7576 called by a hotkey, uses the current location of the crosshair.
7578 @item Import(setnewpoint,mark)
7580 Uses the location of the mark. If no mark is present, the point is
7583 @item Import(setnewpoint,center)
7585 Resets the point to the center of the board.
7587 @item Import(setnewpoint,X,Y,units)
7589 Sets the point to the specific coordinates given. Example:
7590 @code{Import(setnewpoint,50,25,mm)}
7594 Note that the X and Y locations are stored in attributes named
7595 @code{import::newX} and @code{import::newY} so you could change them
7596 manually if you wished.
7598 Calling @code{Import(setdisperse,D,units)} sets how much the newly
7599 placed elements are dispersed relative to the set point. For example,
7600 @code{Import(setdisperse,10,mm)} will offset each part randomly up to
7601 10mm away from the point. The default dispersion is 1/10th of the
7602 smallest board dimension. Dispersion is saved in the
7603 @code{import::disperse} attribute.
7608 ActionImport (int argc
, char **argv
, Coord x
, Coord y
)
7611 char **sources
= NULL
;
7615 printf("ActionImport: =========== Entering ActionImport ============\n");
7620 if (mode
&& strcasecmp (mode
, "setdisperse") == 0)
7629 const char *as
= AttributeGet (PCB
, "import::disperse");
7630 ds
= gui
->prompt_for(_("Enter dispersion:"), as
? as
: "0");
7634 sprintf(buf
, "%s%s", ds
, units
);
7635 AttributePut (PCB
, "import::disperse", buf
);
7638 AttributePut (PCB
, "import::disperse", ds
);
7639 if (ARG (1) == NULL
)
7644 if (mode
&& strcasecmp (mode
, "setnewpoint") == 0)
7646 const char *xs
, *ys
, *units
;
7656 gui
->get_coords (_("Click on a location"), &x
, &y
);
7658 else if (strcasecmp (xs
, "center") == 0)
7660 AttributeRemove (PCB
, "import::newX");
7661 AttributeRemove (PCB
, "import::newY");
7664 else if (strcasecmp (xs
, "mark") == 0)
7674 x
= GetValue (xs
, units
, NULL
);
7675 y
= GetValue (ys
, units
, NULL
);
7679 Message (_("Bad syntax for Import(setnewpoint)"));
7683 pcb_sprintf (buf
, "%$ms", x
);
7684 AttributePut (PCB
, "import::newX", buf
);
7685 pcb_sprintf (buf
, "%$ms", y
);
7686 AttributePut (PCB
, "import::newY", buf
);
7691 mode
= AttributeGet (PCB
, "import::mode");
7698 nsources
= argc
- 1;
7709 sprintf(sname
, "import::src%d", nsources
);
7710 src
= AttributeGet (PCB
, sname
);
7715 sources
= (char **) malloc ((nsources
+ 1) * sizeof (char *));
7719 sprintf(sname
, "import::src%d", nsources
);
7720 src
= AttributeGet (PCB
, sname
);
7721 sources
[nsources
] = src
;
7728 /* Replace .pcb with .sch and hope for the best. */
7729 char *pcbname
= PCB
->Filename
;
7731 char *dot
, *slash
, *bslash
;
7734 return hid_action("ImportGUI");
7736 schname
= (char *) malloc (strlen(pcbname
) + 5);
7737 strcpy (schname
, pcbname
);
7738 dot
= strchr (schname
, '.');
7739 slash
= strchr (schname
, '/');
7740 bslash
= strchr (schname
, '\\');
7741 if (dot
&& slash
&& dot
< slash
)
7743 if (dot
&& bslash
&& dot
< bslash
)
7747 strcat (schname
, ".sch");
7749 if (access (schname
, F_OK
))
7752 return hid_action("ImportGUI");
7755 sources
= (char **) malloc (2 * sizeof (char *));
7756 sources
[0] = schname
;
7761 if (strcasecmp (mode
, "gnetlist") == 0)
7763 char *tmpfile
= tempfile_name_new ("gnetlist_output");
7767 if (tmpfile
== NULL
) {
7768 Message (_("Could not create temp file"));
7772 cmd
= (char **) malloc ((7 + nsources
) * sizeof (char *));
7773 cmd
[0] = Settings
.GnetlistProgram
;
7779 for (i
=0; i
<nsources
; i
++)
7780 cmd
[6+i
] = sources
[i
];
7781 cmd
[6+nsources
] = NULL
;
7784 printf("ActionImport: =========== About to run gnetlist ============\n");
7785 printf("%s %s %s %s %s %s %s ...\n",
7786 cmd
[0], cmd
[1], cmd
[2], cmd
[3], cmd
[4], cmd
[5], cmd
[6]);
7789 if (pcb_spawnvp (cmd
))
7796 printf("ActionImport: =========== About to run ActionExecuteFile, file = %s ============\n", tmpfile
);
7801 ActionExecuteFile (1, cmd
, 0, 0);
7804 tempfile_unlink (tmpfile
);
7806 else if (strcasecmp (mode
, "make") == 0)
7808 int must_free_tmpfile
= 0;
7814 char *user_outfile
= NULL
;
7815 char *user_makefile
= NULL
;
7816 char *user_target
= NULL
;
7819 user_outfile
= AttributeGet (PCB
, "import::outfile");
7820 user_makefile
= AttributeGet (PCB
, "import::makefile");
7821 user_target
= AttributeGet (PCB
, "import::target");
7822 if (user_outfile
&& !user_target
)
7823 user_target
= user_outfile
;
7826 tmpfile
= user_outfile
;
7829 tmpfile
= tempfile_name_new ("gnetlist_output");
7830 if (tmpfile
== NULL
) {
7831 Message (_("Could not create temp file"));
7834 must_free_tmpfile
= 1;
7837 srclen
= sizeof("SRCLIST=") + 2;
7838 for (i
=0; i
<nsources
; i
++)
7839 srclen
+= strlen (sources
[i
]) + 2;
7840 srclist
= (char *) malloc (srclen
);
7841 strcpy (srclist
, "SRCLIST=");
7842 for (i
=0; i
<nsources
; i
++)
7845 strcat (srclist
, " ");
7846 strcat (srclist
, sources
[i
]);
7849 cmd
[0] = Settings
.MakeProgram
;
7851 cmd
[2] = Concat ("PCB=", PCB
->Filename
, NULL
);
7853 cmd
[4] = Concat ("OUT=", tmpfile
, NULL
);
7858 cmd
[i
++] = user_makefile
;
7860 cmd
[i
++] = user_target
? user_target
: (char *)"pcb_import";
7863 if (pcb_spawnvp (cmd
))
7865 if (must_free_tmpfile
)
7875 ActionExecuteFile (1, cmd
, 0, 0);
7880 if (must_free_tmpfile
)
7881 tempfile_unlink (tmpfile
);
7885 Message (_("Unknown import mode: %s\n"), mode
);
7890 AddAllRats (false, NULL
);
7893 printf("ActionImport: =========== Leaving ActionImport ============\n");
7899 /* ------------------------------------------------------------ */
7901 static const char attributes_syntax
[] =
7902 N_("Attributes(Layout|Layer|Element)\n"
7903 "Attributes(Layer,layername)");
7905 static const char attributes_help
[] =
7906 N_("Let the user edit the attributes of the layout, current or given\n"
7907 "layer, or selected element.");
7909 /* %start-doc actions Attributes
7911 This just pops up a dialog letting the user edit the attributes of the
7912 pcb, an element, or a layer.
7918 ActionAttributes (int argc
, char **argv
, Coord x
, Coord y
)
7920 char *function
= ARG (0);
7921 char *layername
= ARG (1);
7927 if (!gui
->edit_attributes
)
7929 Message (_("This GUI doesn't support Attribute Editing\n"));
7933 switch (GetFunctionID (function
))
7937 gui
->edit_attributes(_("Layout Attributes"), &(PCB
->Attributes
));
7943 LayerType
*layer
= CURRENT
;
7948 for (i
=0; i
<max_copper_layer
; i
++)
7949 if (strcmp (PCB
->Data
->Layer
[i
].Name
, layername
) == 0)
7951 layer
= & (PCB
->Data
->Layer
[i
]);
7956 Message (_("No layer named %s\n"), layername
);
7960 buf
= (char *) malloc (strlen (layer
->Name
) +
7961 strlen (_("Layer %s Attributes")));
7962 sprintf (buf
, _("Layer %s Attributes"), layer
->Name
);
7963 gui
->edit_attributes(buf
, &(layer
->Attributes
));
7971 ElementType
*e
= NULL
;
7972 ELEMENT_LOOP (PCB
->Data
);
7974 if (TEST_FLAG (SELECTEDFLAG
, element
))
7983 Message (_("Too many elements selected\n"));
7989 gui
->get_coords (_("Click on an element"), &x
, &y
);
7991 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
7992 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
7993 e
= (ElementType
*) ptrtmp
;
7996 Message (_("No element found there\n"));
8001 if (NAMEONPCB_NAME(e
))
8003 buf
= (char *) malloc (strlen (NAMEONPCB_NAME(e
)) +
8004 strlen (_("Element %s Attributes")));
8005 sprintf(buf
, _("Element %s Attributes"), NAMEONPCB_NAME(e
));
8009 buf
= strdup (_("Unnamed Element Attributes"));
8011 gui
->edit_attributes(buf
, &(e
->Attributes
));
8023 /* --------------------------------------------------------------------------- */
8025 HID_Action action_action_list
[] = {
8026 {"AddRats", 0, ActionAddRats
,
8027 addrats_help
, addrats_syntax
}
8029 {"Attributes", 0, ActionAttributes
,
8030 attributes_help
, attributes_syntax
}
8032 {"Atomic", 0, ActionAtomic
,
8033 atomic_help
, atomic_syntax
}
8035 {"AutoPlaceSelected", 0, ActionAutoPlaceSelected
,
8036 autoplace_help
, autoplace_syntax
}
8038 {"AutoRoute", 0, ActionAutoRoute
,
8039 autoroute_help
, autoroute_syntax
}
8041 {"ChangeClearSize", 0, ActionChangeClearSize
,
8042 changeclearsize_help
, changeclearsize_syntax
}
8044 {"ChangeDrillSize", 0, ActionChange2ndSize
,
8045 changedrillsize_help
, changedrillsize_syntax
}
8047 {"ChangeHole", 0, ActionChangeHole
,
8048 changehold_help
, changehold_syntax
}
8050 {"ChangeJoin", 0, ActionChangeJoin
,
8051 changejoin_help
, changejoin_syntax
}
8053 {"ChangeName", 0, ActionChangeName
,
8054 changename_help
, changename_syntax
}
8056 {"ChangePaste", 0, ActionChangePaste
,
8057 changepaste_help
, changepaste_syntax
}
8059 {"ChangePinName", 0, ActionChangePinName
,
8060 changepinname_help
, changepinname_syntax
}
8062 {"ChangeSize", 0, ActionChangeSize
,
8063 changesize_help
, changesize_syntax
}
8065 {"ChangeSquare", 0, ActionChangeSquare
,
8066 changesquare_help
, changesquare_syntax
}
8068 {"ChangeOctagon", 0, ActionChangeOctagon
,
8069 changeoctagon_help
, changeoctagon_syntax
}
8071 {"ClearSquare", 0, ActionClearSquare
,
8072 clearsquare_help
, clearsquare_syntax
}
8074 {"ClearOctagon", 0, ActionClearOctagon
,
8075 clearoctagon_help
, clearoctagon_syntax
}
8077 {"Connection", 0, ActionConnection
,
8078 connection_help
, connection_syntax
}
8080 {"Delete", 0, ActionDelete
,
8081 delete_help
, delete_syntax
}
8083 {"DeleteRats", 0, ActionDeleteRats
,
8084 deleterats_help
, deleterats_syntax
}
8086 {"DisperseElements", 0, ActionDisperseElements
,
8087 disperseelements_help
, disperseelements_syntax
}
8089 {"Display", 0, ActionDisplay
,
8090 display_help
, display_syntax
}
8092 {"DRC", 0, ActionDRCheck
,
8093 drc_help
, drc_syntax
}
8095 {"DumpLibrary", 0, ActionDumpLibrary
,
8096 dumplibrary_help
, dumplibrary_syntax
}
8098 {"ExecuteFile", 0, ActionExecuteFile
,
8099 executefile_help
, executefile_syntax
}
8101 {"Flip", N_("Click on Object or Flip Point"), ActionFlip
,
8102 flip_help
, flip_syntax
}
8104 {"LoadFrom", 0, ActionLoadFrom
,
8105 loadfrom_help
, loadfrom_syntax
}
8107 {"MarkCrosshair", 0, ActionMarkCrosshair
,
8108 markcrosshair_help
, markcrosshair_syntax
}
8110 {"Message", 0, ActionMessage
,
8111 message_help
, message_syntax
}
8113 {"MinMaskGap", 0, ActionMinMaskGap
,
8114 minmaskgap_help
, minmaskgap_syntax
}
8116 {"MinClearGap", 0, ActionMinClearGap
,
8117 mincleargap_help
, mincleargap_syntax
}
8119 {"Mode", 0, ActionMode
,
8120 mode_help
, mode_syntax
}
8122 {"MorphPolygon", 0, ActionMorphPolygon
,
8123 morphpolygon_help
, morphpolygon_syntax
}
8125 {"PasteBuffer", 0, ActionPasteBuffer
,
8126 pastebuffer_help
, pastebuffer_syntax
}
8128 {"Quit", 0, ActionQuit
,
8129 quit_help
, quit_syntax
}
8131 {"RemoveSelected", 0, ActionRemoveSelected
,
8132 removeselected_help
, removeselected_syntax
}
8134 {"Renumber", 0, ActionRenumber
,
8135 renumber_help
, renumber_syntax
}
8137 {"RipUp", 0, ActionRipUp
,
8138 ripup_help
, ripup_syntax
}
8140 {"Select", 0, ActionSelect
,
8141 select_help
, select_syntax
}
8143 {"Unselect", 0, ActionUnselect
,
8144 unselect_help
, unselect_syntax
}
8146 {"SaveSettings", 0, ActionSaveSettings
,
8147 savesettings_help
, savesettings_syntax
}
8149 {"SaveTo", 0, ActionSaveTo
,
8150 saveto_help
, saveto_syntax
}
8152 {"SetSquare", 0, ActionSetSquare
,
8153 setsquare_help
, setsquare_syntax
}
8155 {"SetOctagon", 0, ActionSetOctagon
,
8156 setoctagon_help
, setoctagon_syntax
}
8158 {"SetThermal", 0, ActionSetThermal
,
8159 setthermal_help
, setthermal_syntax
}
8161 {"SetValue", 0, ActionSetValue
,
8162 setvalue_help
, setvalue_syntax
}
8164 {"ToggleHideName", 0, ActionToggleHideName
,
8165 togglehidename_help
, togglehidename_syntax
}
8167 {"Undo", 0, ActionUndo
,
8168 undo_help
, undo_syntax
}
8170 {"Redo", 0, ActionRedo
,
8171 redo_help
, redo_syntax
}
8173 {"SetSame", N_("Select item to use attributes from"), ActionSetSame
,
8174 setsame_help
, setsame_syntax
}
8176 {"SetFlag", 0, ActionSetFlag
,
8177 setflag_help
, setflag_syntax
}
8179 {"ClrFlag", 0, ActionClrFlag
,
8180 clrflag_help
, clrflag_syntax
}
8182 {"ChangeFlag", 0, ActionChangeFlag
,
8183 changeflag_help
, changeflag_syntax
}
8185 {"Polygon", 0, ActionPolygon
,
8186 polygon_help
, polygon_syntax
}
8188 {"RouteStyle", 0, ActionRouteStyle
,
8189 routestyle_help
, routestyle_syntax
}
8191 {"MoveObject", N_("Select an Object"), ActionMoveObject
,
8192 moveobject_help
, moveobject_syntax
}
8194 {"MoveToCurrentLayer", 0, ActionMoveToCurrentLayer
,
8195 movetocurrentlayer_help
, movetocurrentlayer_syntax
}
8197 {"New", 0, ActionNew
,
8198 new_help
, new_syntax
}
8200 {"pscalib", 0, ActionPSCalib
}
8202 {"ElementList", 0, ActionElementList
,
8203 elementlist_help
, elementlist_syntax
}
8205 {"ElementSetAttr", 0, ActionElementSetAttr
,
8206 elementsetattr_help
, elementsetattr_syntax
}
8208 {"ExecCommand", 0, ActionExecCommand
,
8209 execcommand_help
, execcommand_syntax
}
8211 {"Import", 0, ActionImport
,
8212 import_help
, import_syntax
}
8216 REGISTER_ACTIONS (action_action_list
)