4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
6 * Copyright (C) 1997, 1998, 1999, 2000, 2001 Harry Eaton
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * Contact addresses for paper mail and Email:
23 * Harry Eaton, 6697 Buttonhole Ct, Columbia, MD 21044, USA
24 * haceaton@aplcomm.jhuapl.edu
28 /* action routines for output window
38 #include "autoplace.h"
39 #include "autoroute.h"
45 #include "crosshair.h"
59 /*#include "print.h"*/
64 #include "rubberband.h"
72 #include "pcb-printf.h"
75 #include <stdlib.h> /* rand() */
77 #ifdef HAVE_LIBDMALLOC
81 /* for fork() and friends */
86 #ifdef HAVE_SYS_WAIT_H
90 /* ---------------------------------------------------------------------------
121 F_ElementConnections
,
162 F_ResetLinesAndPolygons
,
163 F_ResetPinsViasAndPads
,
184 F_ToggleAllDirections
,
195 F_ToggleRubberBandMode
,
196 F_ToggleStartDirection
,
201 F_ToggleThindrawPoly
,
215 typedef struct /* used to identify subfunctions */
222 /* --------------------------------------------------------------------------- */
224 /* %start-doc actions 00delta
226 Many actions take a @code{delta} parameter as the last parameter,
227 which is an amount to change something. That @code{delta} may include
228 units, as an additional parameter, such as @code{Action(Object,5,mm)}.
229 If no units are specified, the default is PCB's native units
230 (currently 1/100 mil). Also, if the delta is prefixed by @code{+} or
231 @code{-}, the size is increased or decreased by that amount.
232 Otherwise, the size size is set to the given amount.
236 Action(Object,+0.5,mm)
240 Actions which take a @code{delta} parameter which do not accept all
241 these options will specify what they do take.
245 /* %start-doc actions 00objects
247 Many actions act on indicated objects on the board. They will have
248 parameters like @code{ToggleObject} or @code{SelectedVias} to indicate
249 what group of objects they act on. Unless otherwise specified, these
250 parameters are defined as follows:
256 Affects the object under the mouse pointer. If this action is invoked
257 from a menu or script, the user will be prompted to click on an
258 object, which is then the object affected.
261 @itemx SelectedObjects
263 Affects all objects which are currently selected. At least, all
264 selected objects for which the given action makes sense.
268 @itemx Selected@var{Type}
270 Affects all objects which are both selected and of the @var{Type} specified.
276 /* %start-doc actions 00macros
280 Pins, pads, and vias can have various shapes. All may be round. Pins
281 and pads may be square (obviously "square" pads are usually
282 rectangular). Pins and vias may be octagonal. When you change a
283 shape flag of an element, you actually change all of its pins and
286 Note that the square flag takes precedence over the octagon flag,
287 thus, if both the square and octagon flags are set, the object is
288 square. When the square flag is cleared, the pins and pads will be
289 either round or, if the octagon flag is set, octagonal.
295 /* ---------------------------------------------------------------------------
296 * some local identifiers
298 static PointType InsertedPoint
;
299 static LayerType
*lastLayer
;
312 bool Moving
; /* selected type clicked on */
313 int Hit
; /* move type clicked on */
320 static int defer_updates
= 0;
321 static int defer_needs_update
= 0;
323 static Cardinal polyIndex
= 0;
324 static bool saved_mode
= false;
325 #ifdef HAVE_LIBSTROKE
326 static bool mid_stroke
= false;
327 static BoxType StrokeBox
;
329 static FunctionType Functions
[] = {
330 {"AddSelected", F_AddSelected
},
332 {"AllConnections", F_AllConnections
},
333 {"AllRats", F_AllRats
},
334 {"AllUnusedPins", F_AllUnusedPins
},
338 {"Description", F_Description
},
339 {"Cancel", F_Cancel
},
340 {"Center", F_Center
},
342 {"ClearAndRedraw", F_ClearAndRedraw
},
343 {"ClearList", F_ClearList
},
346 {"Connection", F_Connection
},
347 {"Convert", F_Convert
},
349 {"CycleClip", F_CycleClip
},
350 {"CycleCrosshair", F_CycleCrosshair
},
351 {"DeleteRats", F_DeleteRats
},
353 {"DrillReport", F_DrillReport
},
354 {"Element", F_Element
},
355 {"ElementByName", F_ElementByName
},
356 {"ElementConnections", F_ElementConnections
},
357 {"ElementToBuffer", F_ElementToBuffer
},
358 {"Escape", F_Escape
},
360 {"FlipElement", F_FlipElement
},
361 {"FoundPins", F_FoundPins
},
363 {"InsertPoint", F_InsertPoint
},
365 {"Layout", F_Layout
},
366 {"LayoutAs", F_LayoutAs
},
367 {"LayoutToBuffer", F_LayoutToBuffer
},
369 {"LineSize", F_LineSize
},
371 {"Mirror", F_Mirror
},
373 {"NameOnPCB", F_NameOnPCB
},
374 {"Netlist", F_Netlist
},
375 {"NetByName", F_NetByName
},
377 {"Notify", F_Notify
},
378 {"Object", F_Object
},
379 {"ObjectByName", F_ObjectByName
},
380 {"PasteBuffer", F_PasteBuffer
},
381 {"PadByName", F_PadByName
},
382 {"PinByName", F_PinByName
},
383 {"PinOrPadName", F_PinOrPadName
},
384 {"Pinout", F_Pinout
},
385 {"Polygon", F_Polygon
},
386 {"PolygonHole", F_PolygonHole
},
387 {"PreviousPoint", F_PreviousPoint
},
388 {"RatsNest", F_RatsNest
},
389 {"Rectangle", F_Rectangle
},
390 {"Redraw", F_Redraw
},
391 {"Release", F_Release
},
392 {"Remove", F_Remove
},
393 {"RemoveSelected", F_RemoveSelected
},
394 {"Report", F_Report
},
396 {"ResetLinesAndPolygons", F_ResetLinesAndPolygons
},
397 {"ResetPinsViasAndPads", F_ResetPinsViasAndPads
},
398 {"Restore", F_Restore
},
399 {"Revert", F_Revert
},
400 {"Rotate", F_Rotate
},
402 {"Selected", F_Selected
},
403 {"SelectedArcs", F_SelectedArcs
},
404 {"SelectedElements", F_SelectedElements
},
405 {"SelectedLines", F_SelectedLines
},
406 {"SelectedNames", F_SelectedNames
},
407 {"SelectedObjects", F_SelectedObjects
},
408 {"SelectedPins", F_SelectedPins
},
409 {"SelectedPads", F_SelectedPads
},
410 {"SelectedRats", F_SelectedRats
},
411 {"SelectedTexts", F_SelectedTexts
},
412 {"SelectedVias", F_SelectedVias
},
413 {"Stroke", F_Stroke
},
415 {"TextByName", F_TextByName
},
416 {"TextScale", F_TextScale
},
417 {"Thermal", F_Thermal
},
418 {"ToLayout", F_ToLayout
},
419 {"Toggle45Degree", F_ToggleAllDirections
},
420 {"ToggleClearLine", F_ToggleClearLine
},
421 {"ToggleFullPoly", F_ToggleFullPoly
},
422 {"ToggleGrid", F_ToggleGrid
},
423 {"ToggleMask", F_ToggleMask
},
424 {"ToggleName", F_ToggleName
},
425 {"ToggleObject", F_ToggleObject
},
426 {"ToggleRubberBandMode", F_ToggleRubberBandMode
},
427 {"ToggleStartDirection", F_ToggleStartDirection
},
428 {"ToggleSnapPin", F_ToggleSnapPin
},
429 {"ToggleThindraw", F_ToggleThindraw
},
430 {"ToggleThindrawPoly", F_ToggleThindrawPoly
},
431 {"ToggleLockNames", F_ToggleLockNames
},
432 {"ToggleOnlyNames", F_ToggleOnlyNames
},
433 {"ToggleHideNames", F_ToggleHideNames
},
434 {"ToggleCheckPlanes", F_ToggleCheckPlanes
},
435 {"ToggleLocalRef", F_ToggleLocalRef
},
436 {"ToggleOrthoMove", F_ToggleOrthoMove
},
437 {"ToggleShowDRC", F_ToggleShowDRC
},
438 {"ToggleLiveRoute", F_ToggleLiveRoute
},
439 {"ToggleAutoDRC", F_ToggleAutoDRC
},
440 {"ToggleUniqueNames", F_ToggleUniqueNames
},
443 {"ViaByName", F_ViaByName
},
444 {"ViaSize", F_ViaSize
},
445 {"ViaDrillingHole", F_ViaDrillingHole
},
449 /* ---------------------------------------------------------------------------
450 * some local routines
452 static int GetFunctionID (String
);
453 static void AdjustAttachedBox (void);
454 static void NotifyLine (void);
455 static void NotifyBlock (void);
456 static void NotifyMode (void);
457 static void ClearWarnings (void);
458 #ifdef HAVE_LIBSTROKE
459 static void FinishStroke (void);
460 extern void stroke_init (void);
461 extern void stroke_record (int x
, int y
);
462 extern int stroke_trans (char *s
);
464 static void ChangeFlag (char *, char *, int, char *);
466 #define ARG(n) (argc > (n) ? argv[n] : NULL)
468 #ifdef HAVE_LIBSTROKE
470 /* ---------------------------------------------------------------------------
471 * FinishStroke - try to recognize the stroke sent
479 void *ptr1
, *ptr2
, *ptr3
;
482 if (stroke_trans (msg
))
488 if (Settings
.Mode
== LINE_MODE
)
498 RotateScreenObject (StrokeBox
.X1
, StrokeBox
.Y1
, SWAP_IDENT
? 1 : 3);
504 RotateScreenObject (StrokeBox
.X1
, StrokeBox
.Y1
, SWAP_IDENT
? 3 : 1);
510 SetMode (ARROW_MODE
);
535 /* XXX: FIXME: Call a zoom-extents action */
546 /* XXX: FIXME: Zoom to fit the box StrokeBox.[X1,Y1] - StrokeBox.[X2,Y2] */
550 Message (_("Unknown stroke %s\n"), msg
);
559 /* ---------------------------------------------------------------------------
560 * Clear warning color from pins/pads
565 Settings
.RatWarn
= false;
566 ALLPIN_LOOP (PCB
->Data
);
568 if (TEST_FLAG (WARNFLAG
, pin
))
570 CLEAR_FLAG (WARNFLAG
, pin
);
575 ALLPAD_LOOP (PCB
->Data
);
577 if (TEST_FLAG (WARNFLAG
, pad
))
579 CLEAR_FLAG (WARNFLAG
, pad
);
587 /* ---------------------------------------------------------------------------
589 * This is called a clicktime after a mouse down, to we can distinguish
590 * between short clicks (typically: select or create something) and long
591 * clicks. Long clicks typically drag something.
598 notify_crosshair_change (false);
600 if (Note
.Moving
&& !gui
->shift_is_pressed ())
602 Note
.Buffer
= Settings
.BufferNumber
;
603 SetBufferNumber (MAX_BUFFER
- 1);
604 ClearBuffer (PASTEBUFFER
);
605 AddSelectedToBuffer (PASTEBUFFER
, Note
.X
, Note
.Y
, true);
606 SaveUndoSerialNumber ();
610 SetMode (PASTEBUFFER_MODE
);
612 else if (Note
.Hit
&& !gui
->shift_is_pressed ())
616 SetMode (gui
->control_is_pressed ()? COPY_MODE
: MOVE_MODE
);
617 Crosshair
.AttachedObject
.Ptr1
= Note
.ptr1
;
618 Crosshair
.AttachedObject
.Ptr2
= Note
.ptr2
;
619 Crosshair
.AttachedObject
.Ptr3
= Note
.ptr3
;
620 Crosshair
.AttachedObject
.Type
= Note
.Hit
;
621 AttachForCopy (Note
.X
, Note
.Y
);
629 SaveUndoSerialNumber ();
634 /* unselect first if shift key not down */
635 if (!gui
->shift_is_pressed () && SelectBlock (&box
, false))
636 SetChangedFlag (true);
638 Crosshair
.AttachedBox
.Point1
.X
= Note
.X
;
639 Crosshair
.AttachedBox
.Point1
.Y
= Note
.Y
;
641 notify_crosshair_change (true);
645 /* ---------------------------------------------------------------------------
647 * This is typically called when the mouse has moved or the mouse
648 * button was released.
664 Note
.Click
= false; /* inhibit timer action */
665 SaveUndoSerialNumber ();
666 /* unselect first if shift key not down */
667 if (!gui
->shift_is_pressed ())
669 if (SelectBlock (&box
, false))
670 SetChangedFlag (true);
678 RestoreUndoSerialNumber ();
680 SetChangedFlag (true);
684 else if (Note
.Moving
)
686 RestoreUndoSerialNumber ();
688 ClearBuffer (PASTEBUFFER
);
689 SetBufferNumber (Note
.Buffer
);
698 else if (Settings
.Mode
== ARROW_MODE
)
700 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
701 Crosshair
.AttachedBox
.Point2
.X
);
702 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
703 Crosshair
.AttachedBox
.Point2
.Y
);
704 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
705 Crosshair
.AttachedBox
.Point2
.X
);
706 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
707 Crosshair
.AttachedBox
.Point2
.Y
);
708 RestoreUndoSerialNumber ();
709 if (SelectBlock (&box
, true))
710 SetChangedFlag (true);
712 IncrementUndoSerialNumber ();
713 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
720 /* ---------------------------------------------------------------------------
721 * get function ID of passed string
724 static char function_hash
[HSIZE
];
725 static int hash_initted
= 0;
734 i
= (i
* 13) ^ (unsigned char)tolower((int) *s
);
737 i
= (unsigned int)i
% HSIZE
;
742 GetFunctionID (String Ident
)
752 if (HSIZE
< ENTRIES (Functions
) * 2)
754 fprintf(stderr
, _("Error: function hash size too small (%d vs %lu at %s:%d)\n"),
755 HSIZE
, (unsigned long) ENTRIES (Functions
)*2, __FILE__
, __LINE__
);
758 if (ENTRIES (Functions
) > 254)
760 /* Change 'char' to 'int' and remove this when we get to 256
762 fprintf(stderr
, _("Error: function hash type too small (%d vs %lu at %s:%d)\n"),
763 256, (unsigned long) ENTRIES (Functions
), __FILE__
, __LINE__
);
767 for (i
=ENTRIES (Functions
)-1; i
>=0; i
--)
769 h
= hashfunc (Functions
[i
].Identifier
);
770 while (function_hash
[h
])
772 function_hash
[h
] = i
+ 1;
776 i
= hashfunc (Ident
);
779 /* We enforce the "hash table bigger than function table" rule,
780 so we know there will be at least one zero entry to find. */
781 if (!function_hash
[i
])
783 if (!strcasecmp (Ident
, Functions
[function_hash
[i
]-1].Identifier
))
784 return ((int) Functions
[function_hash
[i
]-1].ID
);
789 /* ---------------------------------------------------------------------------
790 * set new coordinates if in 'RECTANGLE' mode
791 * the cursor shape is also adjusted
794 AdjustAttachedBox (void)
796 if (Settings
.Mode
== ARC_MODE
)
798 Crosshair
.AttachedBox
.otherway
= gui
->shift_is_pressed ();
801 switch (Crosshair
.AttachedBox
.State
)
803 case STATE_SECOND
: /* one corner is selected */
805 /* update coordinates */
806 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
807 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
813 /* ---------------------------------------------------------------------------
814 * adjusts the objects which are to be created like attached lines...
817 AdjustAttachedObjects (void)
820 switch (Settings
.Mode
)
822 /* update at least an attached block (selection) */
825 if (Crosshair
.AttachedBox
.State
)
827 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
828 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
832 /* rectangle creation mode */
835 AdjustAttachedBox ();
838 /* polygon creation mode */
840 case POLYGONHOLE_MODE
:
841 AdjustAttachedLine ();
843 /* line creation mode */
845 if (PCB
->RatDraw
|| PCB
->Clipping
== 0)
846 AdjustAttachedLine ();
848 AdjustTwoLine (PCB
->Clipping
- 1);
850 /* point insertion mode */
851 case INSERTPOINT_MODE
:
852 pnt
= AdjustInsertPoint ();
854 InsertedPoint
= *pnt
;
861 /* ---------------------------------------------------------------------------
862 * creates points of a line
868 void *ptr1
, *ptr2
, *ptr3
;
870 if (!Marked
.status
|| TEST_FLAG (LOCALREFFLAG
, PCB
))
871 SetLocalRef (Crosshair
.X
, Crosshair
.Y
, true);
872 switch (Crosshair
.AttachedLine
.State
)
874 case STATE_FIRST
: /* first point */
875 if (PCB
->RatDraw
&& SearchScreen (Crosshair
.X
, Crosshair
.Y
,
876 PAD_TYPE
| PIN_TYPE
, &ptr1
, &ptr1
,
882 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
884 type
= SearchScreen (Crosshair
.X
, Crosshair
.Y
,
885 PIN_TYPE
| PAD_TYPE
| VIA_TYPE
, &ptr1
, &ptr2
,
887 LookupConnection (Crosshair
.X
, Crosshair
.Y
, true, 1, CONNECTEDFLAG
, false);
888 LookupConnection (Crosshair
.X
, Crosshair
.Y
, true, 1, FOUNDFLAG
, true);
890 if (type
== PIN_TYPE
|| type
== VIA_TYPE
)
892 Crosshair
.AttachedLine
.Point1
.X
=
893 Crosshair
.AttachedLine
.Point2
.X
= ((PinType
*) ptr2
)->X
;
894 Crosshair
.AttachedLine
.Point1
.Y
=
895 Crosshair
.AttachedLine
.Point2
.Y
= ((PinType
*) ptr2
)->Y
;
897 else if (type
== PAD_TYPE
)
899 PadType
*pad
= (PadType
*) ptr2
;
900 double d1
= Distance (Crosshair
.X
, Crosshair
.Y
, pad
->Point1
.X
, pad
->Point1
.Y
);
901 double d2
= Distance (Crosshair
.X
, Crosshair
.Y
, pad
->Point2
.X
, pad
->Point2
.Y
);
904 Crosshair
.AttachedLine
.Point1
=
905 Crosshair
.AttachedLine
.Point2
= pad
->Point2
;
909 Crosshair
.AttachedLine
.Point1
=
910 Crosshair
.AttachedLine
.Point2
= pad
->Point1
;
915 Crosshair
.AttachedLine
.Point1
.X
=
916 Crosshair
.AttachedLine
.Point2
.X
= Crosshair
.X
;
917 Crosshair
.AttachedLine
.Point1
.Y
=
918 Crosshair
.AttachedLine
.Point2
.Y
= Crosshair
.Y
;
920 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
924 /* fall through to third state too */
926 default: /* all following points */
927 Crosshair
.AttachedLine
.State
= STATE_THIRD
;
932 /* ---------------------------------------------------------------------------
933 * create first or second corner of a marked block
938 notify_crosshair_change (false);
939 switch (Crosshair
.AttachedBox
.State
)
941 case STATE_FIRST
: /* setup first point */
942 Crosshair
.AttachedBox
.Point1
.X
=
943 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
944 Crosshair
.AttachedBox
.Point1
.Y
=
945 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
946 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
949 case STATE_SECOND
: /* setup second point */
950 Crosshair
.AttachedBox
.State
= STATE_THIRD
;
953 notify_crosshair_change (true);
957 /* ---------------------------------------------------------------------------
959 * This is called after every mode change, like mouse button pressed,
960 * mouse button released, dragging something started or a different tool
961 * selected. It does what's appropriate for the current mode setting.
962 * This can also mean creation of an object at the current crosshair location.
964 * new created objects are added to the create undo list of course
969 void *ptr1
, *ptr2
, *ptr3
;
972 if (Settings
.RatWarn
)
974 switch (Settings
.Mode
)
982 /* do something after click time */
983 gui
->add_timer (click_cb
, CLICK_TIME
, hv
);
985 /* see if we clicked on something already selected
986 * (Note.Moving) or clicked on a MOVE_TYPE
989 for (test
= (SELECT_TYPES
| MOVE_TYPES
) & ~RATLINE_TYPE
;
992 type
= SearchScreen (Note
.X
, Note
.Y
, test
, &ptr1
, &ptr2
, &ptr3
);
993 if (!Note
.Hit
&& (type
& MOVE_TYPES
) &&
994 !TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
1001 if (!Note
.Moving
&& (type
& SELECT_TYPES
) &&
1002 TEST_FLAG (SELECTEDFLAG
, (PinType
*) ptr2
))
1004 if ((Note
.Hit
&& Note
.Moving
) || type
== NO_TYPE
)
1016 Message (_("You must turn via visibility on before\n"
1017 "you can place vias\n"));
1020 if ((via
= CreateNewVia (PCB
->Data
, Note
.X
, Note
.Y
,
1021 Settings
.ViaThickness
, 2 * Settings
.Keepaway
,
1022 0, Settings
.ViaDrillingHole
, NULL
,
1023 NoFlags ())) != NULL
)
1025 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1026 if (gui
->shift_is_pressed ())
1027 ChangeObjectThermal (VIA_TYPE
, via
, via
, via
, PCB
->ThermStyle
);
1028 IncrementUndoSerialNumber ();
1037 switch (Crosshair
.AttachedBox
.State
)
1040 Crosshair
.AttachedBox
.Point1
.X
=
1041 Crosshair
.AttachedBox
.Point2
.X
= Note
.X
;
1042 Crosshair
.AttachedBox
.Point1
.Y
=
1043 Crosshair
.AttachedBox
.Point2
.Y
= Note
.Y
;
1044 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
1054 wx
= Note
.X
- Crosshair
.AttachedBox
.Point1
.X
;
1055 wy
= Note
.Y
- Crosshair
.AttachedBox
.Point1
.Y
;
1056 if (XOR (Crosshair
.AttachedBox
.otherway
, abs (wy
) > abs (wx
)))
1058 Crosshair
.AttachedBox
.Point2
.X
=
1059 Crosshair
.AttachedBox
.Point1
.X
+ abs (wy
) * SGNZ (wx
);
1060 sa
= (wx
>= 0) ? 0 : 180;
1062 if (abs (wy
) / 2 >= abs (wx
))
1063 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 45 : -45;
1066 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 90 : -90;
1070 Crosshair
.AttachedBox
.Point2
.Y
=
1071 Crosshair
.AttachedBox
.Point1
.Y
+ abs (wx
) * SGNZ (wy
);
1072 sa
= (wy
>= 0) ? -90 : 90;
1074 if (abs (wx
) / 2 >= abs (wy
))
1075 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -45 : 45;
1078 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -90 : 90;
1081 if (abs (wy
) > 0 && (arc
= CreateNewArcOnLayer (CURRENT
,
1105 bx
= GetArcEnds (arc
);
1106 Crosshair
.AttachedBox
.Point1
.X
=
1107 Crosshair
.AttachedBox
.Point2
.X
= bx
->X2
;
1108 Crosshair
.AttachedBox
.Point1
.Y
=
1109 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y2
;
1110 AddObjectToCreateUndoList (ARC_TYPE
, CURRENT
, arc
, arc
);
1111 IncrementUndoSerialNumber ();
1113 DrawArc (CURRENT
, arc
);
1115 Crosshair
.AttachedBox
.State
= STATE_THIRD
;
1124 type
= SearchScreen (Note
.X
, Note
.Y
, LOCK_TYPES
, &ptr1
, &ptr2
, &ptr3
);
1125 if (type
== ELEMENT_TYPE
)
1127 ElementType
*element
= (ElementType
*) ptr2
;
1129 TOGGLE_FLAG (LOCKFLAG
, element
);
1132 TOGGLE_FLAG (LOCKFLAG
, pin
);
1133 CLEAR_FLAG (SELECTEDFLAG
, pin
);
1138 TOGGLE_FLAG (LOCKFLAG
, pad
);
1139 CLEAR_FLAG (SELECTEDFLAG
, pad
);
1142 CLEAR_FLAG (SELECTEDFLAG
, element
);
1143 /* always re-draw it since I'm too lazy
1144 * to tell if a selected flag changed
1146 DrawElement (element
);
1148 SetChangedFlag (true);
1149 hid_actionl ("Report", "Object", NULL
);
1151 else if (type
!= NO_TYPE
)
1153 TextType
*thing
= (TextType
*) ptr3
;
1154 TOGGLE_FLAG (LOCKFLAG
, thing
);
1155 if (TEST_FLAG (LOCKFLAG
, thing
)
1156 && TEST_FLAG (SELECTEDFLAG
, thing
))
1158 /* this is not un-doable since LOCK isn't */
1159 CLEAR_FLAG (SELECTEDFLAG
, thing
);
1160 DrawObject (type
, ptr1
, ptr2
);
1163 SetChangedFlag (true);
1164 hid_actionl ("Report", "Object", NULL
);
1172 SearchScreen (Note
.X
, Note
.Y
, PIN_TYPES
, &ptr1
, &ptr2
,
1174 && !TEST_FLAG (HOLEFLAG
, (PinType
*) ptr3
))
1176 if (gui
->shift_is_pressed ())
1178 int tstyle
= GET_THERM (INDEXOFCURRENT
, (PinType
*) ptr3
);
1182 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, tstyle
);
1184 else if (GET_THERM (INDEXOFCURRENT
, (PinType
*) ptr3
))
1185 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, 0);
1187 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, PCB
->ThermStyle
);
1193 /* do update of position */
1195 if (Crosshair
.AttachedLine
.State
!= STATE_THIRD
)
1198 /* Remove anchor if clicking on start point;
1199 * this means we can't paint 0 length lines
1200 * which could be used for square SMD pads.
1201 * Instead use a very small delta, or change
1202 * the file after saving.
1204 if (Crosshair
.X
== Crosshair
.AttachedLine
.Point1
.X
1205 && Crosshair
.Y
== Crosshair
.AttachedLine
.Point1
.Y
)
1207 SetMode (LINE_MODE
);
1214 if ((line
= AddNet ()))
1217 AddObjectToCreateUndoList (RATLINE_TYPE
, line
, line
, line
);
1218 IncrementUndoSerialNumber ();
1220 Crosshair
.AttachedLine
.Point1
.X
=
1221 Crosshair
.AttachedLine
.Point2
.X
;
1222 Crosshair
.AttachedLine
.Point1
.Y
=
1223 Crosshair
.AttachedLine
.Point2
.Y
;
1229 /* create line if both ends are determined && length != 0 */
1234 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && !TEST_SILK_LAYER (CURRENT
))
1235 line_flags
|= CONNECTEDFLAG
| FOUNDFLAG
;
1237 if (TEST_FLAG (CLEARNEWFLAG
, PCB
))
1238 line_flags
|= CLEARLINEFLAG
;
1241 && Crosshair
.AttachedLine
.Point1
.X
==
1242 Crosshair
.AttachedLine
.Point2
.X
1243 && Crosshair
.AttachedLine
.Point1
.Y
==
1244 Crosshair
.AttachedLine
.Point2
.Y
1245 && (Crosshair
.AttachedLine
.Point2
.X
!= Note
.X
1246 || Crosshair
.AttachedLine
.Point2
.Y
!= Note
.Y
))
1248 /* We will only need to paint the second line segment.
1249 Since we only check for vias on the first segment,
1250 swap them so the non-empty segment is the first segment. */
1251 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1252 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1255 if ((Crosshair
.AttachedLine
.Point1
.X
!=
1256 Crosshair
.AttachedLine
.Point2
.X
1257 || Crosshair
.AttachedLine
.Point1
.Y
!=
1258 Crosshair
.AttachedLine
.Point2
.Y
)
1260 CreateDrawnLineOnLayer (CURRENT
,
1261 Crosshair
.AttachedLine
.Point1
.X
,
1262 Crosshair
.AttachedLine
.Point1
.Y
,
1263 Crosshair
.AttachedLine
.Point2
.X
,
1264 Crosshair
.AttachedLine
.Point2
.Y
,
1265 Settings
.LineThickness
,
1266 2 * Settings
.Keepaway
,
1267 MakeFlags (line_flags
))) != NULL
)
1272 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1273 DrawLine (CURRENT
, line
);
1274 /* place a via if vias are visible, the layer is
1275 in a new group since the last line and there
1276 isn't a pin already here */
1277 if (PCB
->ViaOn
&& GetLayerGroupNumberByPointer (CURRENT
) !=
1278 GetLayerGroupNumberByPointer (lastLayer
) &&
1279 SearchObjectByLocation (PIN_TYPES
, &ptr1
, &ptr2
, &ptr3
,
1280 Crosshair
.AttachedLine
.Point1
.X
,
1281 Crosshair
.AttachedLine
.Point1
.Y
,
1282 Settings
.ViaThickness
/ 2) ==
1285 CreateNewVia (PCB
->Data
,
1286 Crosshair
.AttachedLine
.Point1
.X
,
1287 Crosshair
.AttachedLine
.Point1
.Y
,
1288 Settings
.ViaThickness
,
1289 2 * Settings
.Keepaway
, 0,
1290 Settings
.ViaDrillingHole
, NULL
,
1291 NoFlags ())) != NULL
)
1293 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1296 /* copy the coordinates */
1297 Crosshair
.AttachedLine
.Point1
.X
=
1298 Crosshair
.AttachedLine
.Point2
.X
;
1299 Crosshair
.AttachedLine
.Point1
.Y
=
1300 Crosshair
.AttachedLine
.Point2
.Y
;
1301 IncrementUndoSerialNumber ();
1302 lastLayer
= CURRENT
;
1304 if (PCB
->Clipping
&& (Note
.X
!= Crosshair
.AttachedLine
.Point2
.X
1306 Crosshair
.AttachedLine
.Point2
.Y
)
1308 CreateDrawnLineOnLayer (CURRENT
,
1309 Crosshair
.AttachedLine
.Point2
.X
,
1310 Crosshair
.AttachedLine
.Point2
.Y
,
1312 Settings
.LineThickness
,
1313 2 * Settings
.Keepaway
,
1314 MakeFlags (line_flags
))) != NULL
)
1317 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1318 IncrementUndoSerialNumber ();
1319 DrawLine (CURRENT
, line
);
1320 /* move to new start point */
1321 Crosshair
.AttachedLine
.Point1
.X
= Note
.X
;
1322 Crosshair
.AttachedLine
.Point1
.Y
= Note
.Y
;
1323 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1324 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1325 if (TEST_FLAG (SWAPSTARTDIRFLAG
, PCB
))
1330 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && !TEST_SILK_LAYER (CURRENT
))
1331 LookupConnection (Note
.X
, Note
.Y
, true, 1, CONNECTEDFLAG
, false);
1336 case RECTANGLE_MODE
:
1337 /* do update of position */
1340 /* create rectangle if both corners are determined
1341 * and width, height are != 0
1343 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
1344 Crosshair
.AttachedBox
.Point1
.X
!= Crosshair
.AttachedBox
.Point2
.X
&&
1345 Crosshair
.AttachedBox
.Point1
.Y
!= Crosshair
.AttachedBox
.Point2
.Y
)
1347 PolygonType
*polygon
;
1349 int flags
= CLEARPOLYFLAG
;
1350 if (TEST_FLAG (NEWFULLPOLYFLAG
, PCB
))
1351 flags
|= FULLPOLYFLAG
;
1352 if ((polygon
= CreateNewPolygonFromRectangle (CURRENT
,
1354 AttachedBox
.Point1
.X
,
1356 AttachedBox
.Point1
.Y
,
1358 AttachedBox
.Point2
.X
,
1360 AttachedBox
.Point2
.Y
,
1365 AddObjectToCreateUndoList (POLYGON_TYPE
, CURRENT
,
1367 IncrementUndoSerialNumber ();
1368 DrawPolygon (CURRENT
, polygon
);
1372 /* reset state to 'first corner' */
1373 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
1381 if ((string
= gui
->prompt_for (_("Enter text:"), "")) != NULL
)
1383 if (strlen(string
) > 0)
1386 int flag
= CLEARLINEFLAG
;
1388 if (GetLayerGroupNumberByNumber (INDEXOFCURRENT
) ==
1389 GetLayerGroupNumberBySide (BOTTOM_SIDE
))
1390 flag
|= ONSOLDERFLAG
;
1391 if ((text
= CreateNewText (CURRENT
, &PCB
->Font
, Note
.X
,
1392 Note
.Y
, 0, Settings
.TextScale
,
1393 string
, MakeFlags (flag
))) != NULL
)
1395 AddObjectToCreateUndoList (TEXT_TYPE
, CURRENT
, text
, text
);
1396 IncrementUndoSerialNumber ();
1397 DrawText (CURRENT
, text
);
1408 PointType
*points
= Crosshair
.AttachedPolygon
.Points
;
1409 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1411 /* do update of position; use the 'LINE_MODE' mechanism */
1414 /* check if this is the last point of a polygon */
1416 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1417 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1419 CopyAttachedPolygonToLayer ();
1424 /* create new point if it's the first one or if it's
1425 * different to the last one
1428 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1429 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1431 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1432 Crosshair
.AttachedLine
.Point2
.X
,
1433 Crosshair
.AttachedLine
.Point2
.Y
);
1435 /* copy the coordinates */
1436 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1437 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1442 case POLYGONHOLE_MODE
:
1444 switch (Crosshair
.AttachedObject
.State
)
1446 /* first notify, lookup object */
1448 Crosshair
.AttachedObject
.Type
=
1449 SearchScreen (Note
.X
, Note
.Y
, POLYGON_TYPE
,
1450 &Crosshair
.AttachedObject
.Ptr1
,
1451 &Crosshair
.AttachedObject
.Ptr2
,
1452 &Crosshair
.AttachedObject
.Ptr3
);
1454 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1456 if (TEST_FLAG (LOCKFLAG
, (PolygonType
*)
1457 Crosshair
.AttachedObject
.Ptr2
))
1459 Message (_("Sorry, the object is locked\n"));
1460 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1464 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1468 /* second notify, insert new point into object */
1471 PointType
*points
= Crosshair
.AttachedPolygon
.Points
;
1472 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1473 POLYAREA
*original
, *new_hole
, *result
;
1476 /* do update of position; use the 'LINE_MODE' mechanism */
1479 /* check if this is the last point of a polygon */
1481 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1482 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1484 /* Create POLYAREAs from the original polygon
1485 * and the new hole polygon */
1486 original
= PolygonToPoly ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
);
1487 new_hole
= PolygonToPoly (&Crosshair
.AttachedPolygon
);
1489 /* Subtract the hole from the original polygon shape */
1490 poly_Boolean_free (original
, new_hole
, &result
, PBO_SUB
);
1492 /* Convert the resulting polygon(s) into a new set of nodes
1493 * and place them on the page. Delete the original polygon.
1495 SaveUndoSerialNumber ();
1496 Flags
= ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
)->Flags
;
1497 PolyToPolygonsOnLayer (PCB
->Data
, (LayerType
*)Crosshair
.AttachedObject
.Ptr1
,
1499 RemoveObject (POLYGON_TYPE
,
1500 Crosshair
.AttachedObject
.Ptr1
,
1501 Crosshair
.AttachedObject
.Ptr2
,
1502 Crosshair
.AttachedObject
.Ptr3
);
1503 RestoreUndoSerialNumber ();
1504 IncrementUndoSerialNumber ();
1507 /* reset state of attached line */
1508 memset (&Crosshair
.AttachedPolygon
, 0, sizeof (PolygonType
));
1509 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
1515 /* create new point if it's the first one or if it's
1516 * different to the last one
1519 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1520 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1522 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1523 Crosshair
.AttachedLine
.Point2
.X
,
1524 Crosshair
.AttachedLine
.Point2
.Y
);
1526 /* copy the coordinates */
1527 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1528 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1537 case PASTEBUFFER_MODE
:
1539 TextType estr
[MAX_ELEMENTNAMES
];
1542 if (gui
->shift_is_pressed ())
1545 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1547 if (type
== ELEMENT_TYPE
)
1549 e
= (ElementType
*) ptr1
;
1554 memcpy (estr
, e
->Name
,
1555 MAX_ELEMENTNAMES
* sizeof (TextType
));
1556 for (i
= 0; i
< MAX_ELEMENTNAMES
; ++i
)
1557 estr
[i
].TextString
= estr
[i
].TextString
? strdup(estr
[i
].TextString
) : NULL
;
1562 if (CopyPastebufferToLayout (Note
.X
, Note
.Y
))
1563 SetChangedFlag (true);
1567 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1569 if (type
== ELEMENT_TYPE
&& ptr1
)
1572 e
= (ElementType
*) ptr1
;
1574 save_n
= NAME_INDEX (PCB
);
1576 for (i
= 0; i
< MAX_ELEMENTNAMES
; i
++)
1579 EraseElementName (e
);
1580 r_delete_entry (PCB
->Data
->name_tree
[i
],
1581 (BoxType
*) & (e
->Name
[i
]));
1582 memcpy (&(e
->Name
[i
]), &(estr
[i
]), sizeof (TextType
));
1583 e
->Name
[i
].Element
= e
;
1584 SetTextBoundingBox (&PCB
->Font
, &(e
->Name
[i
]));
1585 r_insert_entry (PCB
->Data
->name_tree
[i
],
1586 (BoxType
*) & (e
->Name
[i
]), 0);
1588 DrawElementName (e
);
1597 SearchScreen (Note
.X
, Note
.Y
, REMOVE_TYPES
, &ptr1
, &ptr2
,
1600 if (TEST_FLAG (LOCKFLAG
, (LineType
*) ptr2
))
1602 Message (_("Sorry, the object is locked\n"));
1605 if (type
== ELEMENT_TYPE
)
1607 RubberbandType
*ptr
;
1610 Crosshair
.AttachedObject
.RubberbandN
= 0;
1611 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
1612 ptr
= Crosshair
.AttachedObject
.Rubberband
;
1613 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
; i
++)
1616 EraseRat ((RatType
*) ptr
->Line
);
1617 if (TEST_FLAG (RUBBERENDFLAG
, ptr
->Line
))
1618 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
1619 ptr
->Line
, ptr
->Line
,
1622 TOGGLE_FLAG (RUBBERENDFLAG
, ptr
->Line
); /* only remove line once */
1626 RemoveObject (type
, ptr1
, ptr2
, ptr3
);
1627 IncrementUndoSerialNumber ();
1628 SetChangedFlag (true);
1633 RotateScreenObject (Note
.X
, Note
.Y
,
1634 gui
->shift_is_pressed ()? (SWAP_IDENT
?
1636 : (SWAP_IDENT
? 3 : 1));
1639 /* both are almost the same */
1642 switch (Crosshair
.AttachedObject
.State
)
1644 /* first notify, lookup object */
1647 int types
= (Settings
.Mode
== COPY_MODE
) ?
1648 COPY_TYPES
: MOVE_TYPES
;
1650 Crosshair
.AttachedObject
.Type
=
1651 SearchScreen (Note
.X
, Note
.Y
, types
,
1652 &Crosshair
.AttachedObject
.Ptr1
,
1653 &Crosshair
.AttachedObject
.Ptr2
,
1654 &Crosshair
.AttachedObject
.Ptr3
);
1655 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1657 if (Settings
.Mode
== MOVE_MODE
&&
1658 TEST_FLAG (LOCKFLAG
, (PinType
*)
1659 Crosshair
.AttachedObject
.Ptr2
))
1661 Message (_("Sorry, the object is locked\n"));
1662 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1665 AttachForCopy (Note
.X
, Note
.Y
);
1670 /* second notify, move or copy object */
1672 if (Settings
.Mode
== COPY_MODE
)
1673 CopyObject (Crosshair
.AttachedObject
.Type
,
1674 Crosshair
.AttachedObject
.Ptr1
,
1675 Crosshair
.AttachedObject
.Ptr2
,
1676 Crosshair
.AttachedObject
.Ptr3
,
1677 Note
.X
- Crosshair
.AttachedObject
.X
,
1678 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1681 MoveObjectAndRubberband (Crosshair
.AttachedObject
.Type
,
1682 Crosshair
.AttachedObject
.Ptr1
,
1683 Crosshair
.AttachedObject
.Ptr2
,
1684 Crosshair
.AttachedObject
.Ptr3
,
1685 Note
.X
- Crosshair
.AttachedObject
.X
,
1686 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1687 SetLocalRef (0, 0, false);
1689 SetChangedFlag (true);
1691 /* reset identifiers */
1692 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1693 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1698 /* insert a point into a polygon/line/... */
1699 case INSERTPOINT_MODE
:
1700 switch (Crosshair
.AttachedObject
.State
)
1702 /* first notify, lookup object */
1704 Crosshair
.AttachedObject
.Type
=
1705 SearchScreen (Note
.X
, Note
.Y
, INSERT_TYPES
,
1706 &Crosshair
.AttachedObject
.Ptr1
,
1707 &Crosshair
.AttachedObject
.Ptr2
,
1708 &Crosshair
.AttachedObject
.Ptr3
);
1710 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1712 if (TEST_FLAG (LOCKFLAG
, (PolygonType
*)
1713 Crosshair
.AttachedObject
.Ptr2
))
1715 Message (_("Sorry, the object is locked\n"));
1716 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1721 /* get starting point of nearest segment */
1722 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1725 (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
;
1727 GetLowestDistancePolygonPoint (fake
.poly
, Note
.X
,
1729 fake
.line
.Point1
= fake
.poly
->Points
[polyIndex
];
1730 fake
.line
.Point2
= fake
.poly
->Points
[
1731 prev_contour_point (fake
.poly
, polyIndex
)];
1732 Crosshair
.AttachedObject
.Ptr2
= &fake
.line
;
1735 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1736 InsertedPoint
= *AdjustInsertPoint ();
1741 /* second notify, insert new point into object */
1743 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1744 InsertPointIntoObject (POLYGON_TYPE
,
1745 Crosshair
.AttachedObject
.Ptr1
, fake
.poly
,
1747 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1749 InsertPointIntoObject (Crosshair
.AttachedObject
.Type
,
1750 Crosshair
.AttachedObject
.Ptr1
,
1751 Crosshair
.AttachedObject
.Ptr2
,
1753 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1754 SetChangedFlag (true);
1756 /* reset identifiers */
1757 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1758 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1766 /* --------------------------------------------------------------------------- */
1768 static const char atomic_syntax
[] = N_("Atomic(Save|Restore|Close|Block)");
1770 static const char atomic_help
[] = N_("Save or restore the undo serial number.");
1772 /* %start-doc actions Atomic
1774 This action allows making multiple-action bindings into an atomic
1775 operation that will be undone by a single Undo command. For example,
1776 to optimize rat lines, you'd delete the rats and re-add them. To
1777 group these into a single undo, you'd want the deletions and the
1778 additions to have the same undo serial number. So, you @code{Save},
1779 delete the rats, @code{Restore}, add the rats - using the same serial
1780 number as the deletes, then @code{Block}, which checks to see if the
1781 deletions or additions actually did anything. If not, the serial
1782 number is set to the saved number, as there's nothing to undo. If
1783 something did happen, the serial number is incremented so that these
1784 actions are counted as a single undo step.
1789 Saves the undo serial number.
1792 Returns it to the last saved number.
1795 Sets it to 1 greater than the last save.
1798 Does a Restore if there was nothing to undo, else does a Close.
1805 ActionAtomic (int argc
, char **argv
, Coord x
, Coord y
)
1810 switch (GetFunctionID (argv
[0]))
1813 SaveUndoSerialNumber ();
1816 RestoreUndoSerialNumber ();
1819 RestoreUndoSerialNumber ();
1820 IncrementUndoSerialNumber ();
1823 RestoreUndoSerialNumber ();
1825 IncrementUndoSerialNumber ();
1831 /* -------------------------------------------------------------------------- */
1833 static const char drc_syntax
[] = N_("DRC()");
1835 static const char drc_help
[] = N_("Invoke the DRC check.");
1837 /* %start-doc actions DRC
1839 Note that the design rule check uses the current board rule settings,
1840 not the current style settings.
1845 ActionDRCheck (int argc
, char **argv
, Coord x
, Coord y
)
1849 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1851 Message (_("%m+Rules are minspace %$mS, minoverlap %$mS "
1852 "minwidth %$mS, minsilk %$mS\n"
1853 "min drill %$mS, min annular ring %$mS\n"),
1854 Settings
.grid_unit
->allow
,
1855 PCB
->Bloat
, PCB
->Shrink
,
1856 PCB
->minWid
, PCB
->minSlk
,
1857 PCB
->minDrill
, PCB
->minRing
);
1860 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1863 Message (_("No DRC problems found.\n"));
1865 Message (_("Found %d design rule errors.\n"), count
);
1867 Message (_("Aborted DRC after %d design rule errors.\n"), -count
);
1872 /* -------------------------------------------------------------------------- */
1874 static const char dumplibrary_syntax
[] = N_("DumpLibrary()");
1876 static const char dumplibrary_help
[] =
1877 N_("Display the entire contents of the libraries.");
1879 /* %start-doc actions DumpLibrary
1885 ActionDumpLibrary (int argc
, char **argv
, Coord x
, Coord y
)
1889 printf ("**** Do not count on this format. It will change ****\n\n");
1890 printf ("MenuN = %d\n", Library
.MenuN
);
1891 printf ("MenuMax = %d\n", Library
.MenuMax
);
1892 for (i
= 0; i
< Library
.MenuN
; i
++)
1894 printf ("Library #%d:\n", i
);
1895 printf (" EntryN = %d\n", Library
.Menu
[i
].EntryN
);
1896 printf (" EntryMax = %d\n", Library
.Menu
[i
].EntryMax
);
1897 printf (" Name = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Name
));
1898 printf (" directory = \"%s\"\n",
1899 UNKNOWN (Library
.Menu
[i
].directory
));
1900 printf (" Style = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Style
));
1901 printf (" flag = %d\n", Library
.Menu
[i
].flag
);
1903 for (j
= 0; j
< Library
.Menu
[i
].EntryN
; j
++)
1905 printf (" #%4d: ", j
);
1906 if (Library
.Menu
[i
].Entry
[j
].Template
== (char *) -1)
1908 printf ("newlib: \"%s\"\n",
1909 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
));
1913 printf ("\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"\n",
1914 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
),
1915 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Template
),
1916 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Package
),
1917 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Value
),
1918 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Description
));
1926 /* -------------------------------------------------------------------------- */
1928 static const char flip_syntax
[] = N_("Flip(Object|Selected|SelectedElements)");
1930 static const char flip_help
[] =
1931 N_("Flip an element to the opposite side of the board.");
1933 /* %start-doc actions Flip
1935 Note that the location of the element will be symmetric about the
1936 cursor location; i.e. if the part you are pointing at will still be at
1937 the same spot once the element is on the other side. When flipping
1938 multiple elements, this retains their positions relative to each
1939 other, not their absolute positions on the board.
1944 ActionFlip (int argc
, char **argv
, Coord x
, Coord y
)
1946 char *function
= ARG (0);
1947 ElementType
*element
;
1953 switch (GetFunctionID (function
))
1956 if ((SearchScreen (x
, y
, ELEMENT_TYPE
,
1957 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
1959 element
= (ElementType
*) ptrtmp
;
1960 ChangeElementSide (element
, 2 * Crosshair
.Y
- PCB
->MaxHeight
);
1961 IncrementUndoSerialNumber ();
1966 case F_SelectedElements
:
1967 ChangeSelectedElementSide ();
1980 /* -------------------------------------------------------------------------- */
1982 static const char message_syntax
[] = N_("Message(message)");
1984 static const char message_help
[] = N_("Writes a message to the log window.");
1986 /* %start-doc actions Message
1988 This action displays a message to the log window. This action is primarily
1989 provided for use by other programs which may interface with PCB. If
1990 multiple arguments are given, each one is sent to the log window
1991 followed by a newline.
1996 ActionMessage (int argc
, char **argv
, Coord x
, Coord y
)
2003 for (i
= 0; i
< argc
; i
++)
2013 /* -------------------------------------------------------------------------- */
2015 static const char setthermal_syntax
[] =
2016 "SetThermal(Object|SelectedPins|SelectedVias|Selected, Style)";
2018 static const char setthermal_help
[] =
2019 N_("Set the thermal (on the current layer) of pins or vias to the given style.\n"
2020 "Style = 0 means no thermal.\n"
2021 "Style = 1 has diagonal fingers with sharp edges.\n"
2022 "Style = 2 has horizontal and vertical fingers with sharp edges.\n"
2023 "Style = 3 is a solid connection to the plane."
2024 "Style = 4 has diagonal fingers with rounded edges.\n"
2025 "Style = 5 has horizontal and vertical fingers with rounded edges.\n");
2027 /* %start-doc actions SetThermal
2029 This changes how/whether pins or vias connect to any rectangle or polygon
2030 on the current layer. The first argument can specify one object, or all
2031 selected pins, or all selected vias, or all selected pins and vias.
2032 The second argument specifies the style of connection.
2033 There are 5 possibilities:
2035 1 - 45 degree fingers with sharp edges,
2036 2 - horizontal & vertical fingers with sharp edges,
2037 3 - solid connection,
2038 4 - 45 degree fingers with rounded corners,
2039 5 - horizontal & vertical fingers with rounded corners.
2041 Pins and Vias may have thermals whether or not there is a polygon available
2042 to connect with. However, they will have no effect without the polygon.
2046 ActionSetThermal (int argc
, char **argv
, Coord x
, Coord y
)
2048 char *function
= ARG (0);
2049 char *style
= ARG (1);
2050 void *ptr1
, *ptr2
, *ptr3
;
2054 if (function
&& *function
&& style
&& *style
)
2058 kind
= GetValue (style
, NULL
, &absolute
);
2060 switch (GetFunctionID (function
))
2064 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGETHERMAL_TYPES
,
2065 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
2067 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, kind
);
2068 IncrementUndoSerialNumber ();
2072 case F_SelectedPins
:
2073 ChangeSelectedThermals (PIN_TYPE
, kind
);
2075 case F_SelectedVias
:
2076 ChangeSelectedThermals (VIA_TYPE
, kind
);
2079 case F_SelectedElements
:
2080 ChangeSelectedThermals (CHANGETHERMAL_TYPES
, kind
);
2095 /* ---------------------------------------------------------------------------
2096 * !!! no action routine !!!
2098 * event handler to set the cursor according to the X pointer position
2099 * called from inside main.c
2102 EventMoveCrosshair (int ev_x
, int ev_y
)
2104 #ifdef HAVE_LIBSTROKE
2107 StrokeBox
.X2
= ev_x
;
2108 StrokeBox
.Y2
= ev_y
;
2109 stroke_record (ev_x
, ev_y
);
2112 #endif /* HAVE_LIBSTROKE */
2113 if (MoveCrosshairAbsolute (ev_x
, ev_y
))
2115 /* update object position and cursor location */
2116 AdjustAttachedObjects ();
2117 notify_crosshair_change (true);
2121 /* --------------------------------------------------------------------------- */
2123 static const char setvalue_syntax
[] =
2124 N_("SetValue(Grid|Line|LineSize|Text|TextScale|ViaDrillingHole|Via|ViaSize, "
2127 static const char setvalue_help
[] =
2128 N_("Change various board-wide values and sizes.");
2130 /* %start-doc actions SetValue
2134 @item ViaDrillingHole
2135 Changes the diameter of the drill for new vias.
2138 Sets the grid spacing.
2142 Changes the thickness of new lines.
2146 Changes the diameter of new vias.
2150 Changes the size of new text.
2157 ActionSetValue (int argc
, char **argv
, Coord x
, Coord y
)
2159 char *function
= ARG (0);
2160 char *val
= ARG (1);
2161 char *units
= ARG (2);
2162 bool absolute
; /* flag for 'absolute' value */
2167 if (function
&& val
)
2169 value
= GetValue (val
, units
, &absolute
);
2170 switch (GetFunctionID (function
))
2172 case F_ViaDrillingHole
:
2173 SetViaDrillingHole (absolute
? value
:
2174 value
+ Settings
.ViaDrillingHole
,
2176 hid_action ("RouteStylesChanged");
2181 SetGrid (value
, false);
2185 value
= val
[0] == '-' ? -Settings
.increments
->grid
2186 : Settings
.increments
->grid
;
2187 /* On the way down, short against the minimum
2188 * PCB drawing unit */
2189 if ((value
+ PCB
->Grid
) < 1)
2191 else if (PCB
->Grid
== 1)
2192 SetGrid (value
, false);
2194 SetGrid (value
+ PCB
->Grid
, false);
2200 if (!absolute
&& value
== 0)
2201 value
= val
[0] == '-' ? -Settings
.increments
->line
2202 : Settings
.increments
->line
;
2203 SetLineSize (absolute
? value
: value
+ Settings
.LineThickness
);
2204 hid_action ("RouteStylesChanged");
2209 SetViaSize (absolute
? value
: value
+ Settings
.ViaThickness
, false);
2210 hid_action ("RouteStylesChanged");
2215 text_scale
= value
/ (double)FONT_CAPHEIGHT
* 100.;
2217 text_scale
+= Settings
.TextScale
;
2218 SetTextScale (text_scale
);
2232 /* --------------------------------------------------------------------------- */
2234 static const char quit_syntax
[] = N_("Quit()");
2236 static const char quit_help
[] = N_("Quits the application after confirming.");
2238 /* %start-doc actions Quit
2240 If you have unsaved changes, you will be prompted to confirm (or
2241 save) before quitting.
2246 ActionQuit (int argc
, char **argv
, Coord x
, Coord y
)
2248 char *force
= ARG (0);
2249 if (force
&& strcasecmp (force
, "force") == 0)
2254 if (!PCB
->Changed
|| gui
->close_confirm_dialog () == HID_CLOSE_CONFIRM_OK
)
2259 /* --------------------------------------------------------------------------- */
2261 static const char connection_syntax
[] =
2262 N_("Connection(Find|ResetLinesAndPolygons|ResetPinsAndVias|Reset)");
2264 static const char connection_help
[] =
2265 N_("Searches connections of the object at the cursor position.");
2267 /* %start-doc actions Connection
2269 Connections found with this action will be highlighted in the
2270 ``connected-color'' color and will have the ``found'' flag set.
2275 The net under the cursor is ``found''.
2277 @item ResetLinesAndPolygons
2278 Any ``found'' lines and polygons are marked ``not found''.
2280 @item ResetPinsAndVias
2281 Any ``found'' pins and vias are marked ``not found''.
2284 All ``found'' objects are marked ``not found''.
2291 ActionConnection (int argc
, char **argv
, Coord x
, Coord y
)
2293 char *function
= ARG (0);
2296 switch (GetFunctionID (function
))
2300 gui
->get_coords (_("Click on a connection"), &x
, &y
);
2301 LookupConnection (x
, y
, true, 1, CONNECTEDFLAG
, false);
2302 LookupConnection (x
, y
, true, 1, FOUNDFLAG
, true);
2306 case F_ResetLinesAndPolygons
:
2307 if (ClearFlagOnLinesAndPolygons (true, CONNECTEDFLAG
| FOUNDFLAG
))
2309 IncrementUndoSerialNumber ();
2314 case F_ResetPinsViasAndPads
:
2315 if (ClearFlagOnPinsViasAndPads (true, CONNECTEDFLAG
| FOUNDFLAG
))
2317 IncrementUndoSerialNumber ();
2323 if (ClearFlagOnAllObjects (true, CONNECTEDFLAG
| FOUNDFLAG
))
2325 IncrementUndoSerialNumber ();
2336 /* --------------------------------------------------------------------------- */
2338 static const char disperseelements_syntax
[] =
2339 N_("DisperseElements(All|Selected)");
2341 static const char disperseelements_help
[] = N_("Disperses elements.");
2343 /* %start-doc actions DisperseElements
2345 Normally this is used when starting a board, by selecting all elements
2346 and then dispersing them. This scatters the elements around the board
2347 so that you can pick individual ones, rather than have all the
2348 elements at the same 0,0 coordinate and thus impossible to choose
2353 #define GAP MIL_TO_COORD(100)
2356 ActionDisperseElements (int argc
, char **argv
, Coord x
, Coord y
)
2358 char *function
= ARG (0);
2363 int all
= 0, bad
= 0;
2365 if (!function
|| !*function
)
2371 switch (GetFunctionID (function
))
2388 AFAIL (disperseelements
);
2392 ELEMENT_LOOP (PCB
->Data
);
2395 * If we want to disperse selected elements, maybe we need smarter
2396 * code here to avoid putting components on top of others which
2397 * are not selected. For now, I'm assuming that this is typically
2398 * going to be used either with a brand new design or a scratch
2399 * design holding some new components
2401 if (!TEST_FLAG (LOCKFLAG
, element
) && (all
|| TEST_FLAG (SELECTEDFLAG
, element
)))
2404 /* figure out how much to move the element */
2405 dx
= minx
- element
->BoundingBox
.X1
;
2407 /* snap to the grid */
2408 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2411 * and add one grid size so we make sure we always space by GAP or
2416 /* Figure out if this row has room. If not, start a new row */
2417 if (GAP
+ element
->BoundingBox
.X2
+ dx
> PCB
->MaxWidth
)
2423 /* figure out how much to move the element */
2424 dx
= minx
- element
->BoundingBox
.X1
;
2425 dy
= miny
- element
->BoundingBox
.Y1
;
2427 /* snap to the grid */
2428 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2430 dy
-= (element
->MarkY
+ dy
) % PCB
->Grid
;
2433 /* move the element */
2434 MoveElementLowLevel (PCB
->Data
, element
, dx
, dy
);
2436 /* and add to the undo list so we can undo this operation */
2437 AddObjectToMoveUndoList (ELEMENT_TYPE
, NULL
, NULL
, element
, dx
, dy
);
2439 /* keep track of how tall this row is */
2440 minx
+= element
->BoundingBox
.X2
- element
->BoundingBox
.X1
+ GAP
;
2441 if (maxy
< element
->BoundingBox
.Y2
)
2443 maxy
= element
->BoundingBox
.Y2
;
2450 /* done with our action so increment the undo # */
2451 IncrementUndoSerialNumber ();
2454 SetChangedFlag (true);
2461 /* --------------------------------------------------------------------------- */
2463 static const char display_syntax
[] =
2464 N_("Display(NameOnPCB|Description|Value)\n"
2465 "Display(Grid|Redraw)\n"
2466 "Display(CycleClip|CycleCrosshair|Toggle45Degree|ToggleStartDirection)\n"
2467 "Display(ToggleGrid|ToggleRubberBandMode|ToggleUniqueNames)\n"
2468 "Display(ToggleMask|ToggleName|ToggleClearLine|ToggleFullPoly|ToggleSnapPin)\n"
2469 "Display(ToggleThindraw|ToggleThindrawPoly|ToggleOrthoMove|ToggleLocalRef)\n"
2470 "Display(ToggleCheckPlanes|ToggleShowDRC|ToggleAutoDRC)\n"
2471 "Display(ToggleLiveRoute|LockNames|OnlyNames)\n"
2472 "Display(Pinout|PinOrPadName)");
2474 static const char display_help
[] = N_("Several display-related actions.");
2476 /* %start-doc actions Display
2483 Specify whether all elements show their name, description, or value.
2486 Redraw the whole board.
2488 @item Toggle45Degree
2489 When clear, lines can be drawn at any angle. When set, lines are
2490 restricted to multiples of 45 degrees and requested lines may be
2491 broken up according to the clip setting.
2494 Changes the way lines are restricted to 45 degree increments. The
2495 various settings are: straight only, orthogonal then angled, and angled
2496 then orthogonal. If AllDirections is set, this action disables it.
2498 @item CycleCrosshair
2499 Changes crosshair drawing. Crosshair may accept form of 4-ray,
2500 8-ray and 12-ray cross.
2502 @item ToggleRubberBandMode
2503 If set, moving an object moves all the lines attached to it too.
2505 @item ToggleStartDirection
2506 If set, each time you set a point in a line, the Clip toggles between
2507 orth-angle and angle-ortho.
2509 @item ToggleUniqueNames
2510 If set, you will not be permitted to change the name of an element to
2511 match that of another element.
2514 If set, pin centers and pad end points are treated as additional grid
2515 points that the cursor can snap to.
2517 @item ToggleLocalRef
2518 If set, the mark is automatically set to the beginning of any move, so
2519 you can see the relative distance you've moved.
2521 @item ToggleThindraw
2522 If set, objects on the screen are drawn as outlines (lines are drawn
2523 as center-lines). This lets you see line endpoints hidden under pins,
2526 @item ToggleThindrawPoly
2527 If set, polygons on the screen are drawn as outlines.
2530 If set, pending objects (i.e. lines you're in the process of drawing)
2531 will be drawn with an outline showing how far away from other copper
2534 @item ToggleLiveRoute
2535 If set, the progress of the autorouter will be visible on the screen.
2538 If set, you will not be permitted to make connections which violate
2539 the current DRC and netlist settings.
2541 @item ToggleCheckPlanes
2542 If set, lines and arcs aren't drawn, which usually leaves just the
2543 polygons. If you also disable all but the layer you're interested in,
2544 this allows you to check for isolated regions.
2546 @item ToggleOrthoMove
2547 If set, the crosshair is only allowed to move orthogonally from its
2548 previous position. I.e. you can move an element or line up, down,
2549 left, or right, but not up+left or down+right.
2552 Selects whether the pinouts show the pin names or the pin numbers.
2554 @item ToggleLockNames
2555 If set, text will ignore left mouse clicks and actions that work on
2556 objects under the mouse. You can still select text with a lasso (left
2557 mouse drag) and perform actions on the selection.
2559 @item ToggleOnlyNames
2560 If set, only text will be sensitive for mouse clicks and actions that
2561 work on objects under the mouse. You can still select other objects
2562 with a lasso (left mouse drag) and perform actions on the selection.
2565 Turns the solder mask on or off.
2567 @item ToggleClearLine
2568 When set, the clear-line flag causes new lines and arcs to have their
2569 ``clear polygons'' flag set, so they won't be electrically connected
2570 to any polygons they overlap.
2572 @item ToggleFullPoly
2573 When set, the full-poly flag causes new polygons to have their
2574 ``full polygon'' flag set, so all parts of them will be displayed
2575 instead of only the biggest one.
2578 Resets the origin of the current grid to be wherever the mouse pointer
2579 is (not where the crosshair currently is). If you provide two numbers
2580 after this, the origin is set to that coordinate.
2583 Toggles whether the grid is displayed or not.
2586 Causes the pinout of the element indicated by the cursor to be
2587 displayed, usually in a separate window.
2590 Toggles whether the names of pins, pads, or (yes) vias will be
2591 displayed. If the cursor is over an element, all of its pins and pads
2598 static enum crosshair_shape
2599 CrosshairShapeIncrement (enum crosshair_shape shape
)
2603 case Basic_Crosshair_Shape
:
2604 shape
= Union_Jack_Crosshair_Shape
;
2606 case Union_Jack_Crosshair_Shape
:
2607 shape
= Dozen_Crosshair_Shape
;
2609 case Dozen_Crosshair_Shape
:
2610 shape
= Crosshair_Shapes_Number
;
2612 case Crosshair_Shapes_Number
:
2613 shape
= Basic_Crosshair_Shape
;
2620 ActionDisplay (int argc
, char **argv
, Coord childX
, Coord childY
)
2622 char *function
, *str_dir
;
2629 if (function
&& (!str_dir
|| !*str_dir
))
2631 switch (id
= GetFunctionID (function
))
2635 case F_ClearAndRedraw
:
2640 /* change the displayed name of elements */
2644 ELEMENT_LOOP (PCB
->Data
);
2646 EraseElementName (element
);
2649 CLEAR_FLAG (DESCRIPTIONFLAG
| NAMEONPCBFLAG
, PCB
);
2655 SET_FLAG (NAMEONPCBFLAG
, PCB
);
2658 SET_FLAG (DESCRIPTIONFLAG
, PCB
);
2661 ELEMENT_LOOP (PCB
->Data
);
2663 DrawElementName (element
);
2669 /* toggle line-adjust flag */
2670 case F_ToggleAllDirections
:
2671 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2672 AdjustAttachedObjects ();
2676 notify_crosshair_change (false);
2677 if (TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
2679 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2683 PCB
->Clipping
= (PCB
->Clipping
+ 1) % 3;
2684 AdjustAttachedObjects ();
2685 notify_crosshair_change (true);
2688 case F_CycleCrosshair
:
2689 notify_crosshair_change (false);
2690 Crosshair
.shape
= CrosshairShapeIncrement(Crosshair
.shape
);
2691 if (Crosshair_Shapes_Number
== Crosshair
.shape
)
2692 Crosshair
.shape
= Basic_Crosshair_Shape
;
2693 notify_crosshair_change (true);
2696 case F_ToggleRubberBandMode
:
2697 notify_crosshair_change (false);
2698 TOGGLE_FLAG (RUBBERBANDFLAG
, PCB
);
2699 notify_crosshair_change (true);
2702 case F_ToggleStartDirection
:
2703 notify_crosshair_change (false);
2704 TOGGLE_FLAG (SWAPSTARTDIRFLAG
, PCB
);
2705 notify_crosshair_change (true);
2708 case F_ToggleUniqueNames
:
2709 TOGGLE_FLAG (UNIQUENAMEFLAG
, PCB
);
2712 case F_ToggleSnapPin
:
2713 notify_crosshair_change (false);
2714 TOGGLE_FLAG (SNAPPINFLAG
, PCB
);
2715 notify_crosshair_change (true);
2718 case F_ToggleLocalRef
:
2719 TOGGLE_FLAG (LOCALREFFLAG
, PCB
);
2722 case F_ToggleThindraw
:
2723 TOGGLE_FLAG (THINDRAWFLAG
, PCB
);
2727 case F_ToggleThindrawPoly
:
2728 TOGGLE_FLAG (THINDRAWPOLYFLAG
, PCB
);
2732 case F_ToggleLockNames
:
2733 TOGGLE_FLAG (LOCKNAMESFLAG
, PCB
);
2734 CLEAR_FLAG (ONLYNAMESFLAG
, PCB
);
2737 case F_ToggleOnlyNames
:
2738 TOGGLE_FLAG (ONLYNAMESFLAG
, PCB
);
2739 CLEAR_FLAG (LOCKNAMESFLAG
, PCB
);
2742 case F_ToggleHideNames
:
2743 TOGGLE_FLAG (HIDENAMESFLAG
, PCB
);
2747 case F_ToggleShowDRC
:
2748 TOGGLE_FLAG (SHOWDRCFLAG
, PCB
);
2751 case F_ToggleLiveRoute
:
2752 TOGGLE_FLAG (LIVEROUTEFLAG
, PCB
);
2755 case F_ToggleAutoDRC
:
2756 notify_crosshair_change (false);
2757 TOGGLE_FLAG (AUTODRCFLAG
, PCB
);
2758 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
2760 if (ClearFlagOnAllObjects (true, CONNECTEDFLAG
| FOUNDFLAG
))
2762 IncrementUndoSerialNumber ();
2765 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
2767 LookupConnection (Crosshair
.AttachedLine
.Point1
.X
,
2768 Crosshair
.AttachedLine
.Point1
.Y
,
2769 true, 1, CONNECTEDFLAG
, false);
2770 LookupConnection (Crosshair
.AttachedLine
.Point1
.X
,
2771 Crosshair
.AttachedLine
.Point1
.Y
,
2772 true, 1, FOUNDFLAG
, true);
2775 notify_crosshair_change (true);
2778 case F_ToggleCheckPlanes
:
2779 TOGGLE_FLAG (CHECKPLANESFLAG
, PCB
);
2783 case F_ToggleOrthoMove
:
2784 TOGGLE_FLAG (ORTHOMOVEFLAG
, PCB
);
2788 TOGGLE_FLAG (SHOWNUMBERFLAG
, PCB
);
2793 TOGGLE_FLAG (SHOWMASKFLAG
, PCB
);
2797 case F_ToggleClearLine
:
2798 TOGGLE_FLAG (CLEARNEWFLAG
, PCB
);
2801 case F_ToggleFullPoly
:
2802 TOGGLE_FLAG (NEWFULLPOLYFLAG
, PCB
);
2805 /* shift grid alignment */
2808 Coord oldGrid
= PCB
->Grid
;
2811 if (MoveCrosshairAbsolute (Crosshair
.X
, Crosshair
.Y
))
2812 notify_crosshair_change (true); /* first notify was in MoveCrosshairAbs */
2813 SetGrid (oldGrid
, true);
2817 /* toggle displaying of the grid */
2819 Settings
.DrawGrid
= !Settings
.DrawGrid
;
2823 /* display the pinout of an element */
2826 ElementType
*element
;
2830 gui
->get_coords (_("Click on an element"), &x
, &y
);
2832 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
2833 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
2835 element
= (ElementType
*) ptrtmp
;
2836 gui
->show_item (element
);
2841 /* toggle displaying of pin/pad/via names */
2842 case F_PinOrPadName
:
2844 void *ptr1
, *ptr2
, *ptr3
;
2846 switch (SearchScreen (Crosshair
.X
, Crosshair
.Y
,
2847 ELEMENT_TYPE
| PIN_TYPE
| PAD_TYPE
|
2848 VIA_TYPE
, (void **) &ptr1
, (void **) &ptr2
,
2852 PIN_LOOP ((ElementType
*) ptr1
);
2854 if (TEST_FLAG (DISPLAYNAMEFLAG
, pin
))
2858 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, pin
, pin
);
2859 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pin
);
2862 PAD_LOOP ((ElementType
*) ptr1
);
2864 if (TEST_FLAG (DISPLAYNAMEFLAG
, pad
))
2868 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, pad
, pad
);
2869 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pad
);
2872 SetChangedFlag (true);
2873 IncrementUndoSerialNumber ();
2878 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
))
2879 ErasePinName ((PinType
*) ptr2
);
2881 DrawPinName ((PinType
*) ptr2
);
2882 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, ptr2
, ptr3
);
2883 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
);
2884 SetChangedFlag (true);
2885 IncrementUndoSerialNumber ();
2890 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PadType
*) ptr2
))
2891 ErasePadName ((PadType
*) ptr2
);
2893 DrawPadName ((PadType
*) ptr2
);
2894 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, ptr2
, ptr3
);
2895 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PadType
*) ptr2
);
2896 SetChangedFlag (true);
2897 IncrementUndoSerialNumber ();
2901 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
))
2902 EraseViaName ((PinType
*) ptr2
);
2904 DrawViaName ((PinType
*) ptr2
);
2905 AddObjectToFlagUndoList (VIA_TYPE
, ptr1
, ptr2
, ptr3
);
2906 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
);
2907 SetChangedFlag (true);
2908 IncrementUndoSerialNumber ();
2918 else if (function
&& str_dir
)
2920 switch (GetFunctionID (function
))
2925 PCB
->GridOffsetX
= GetValue (argv
[1], NULL
, NULL
);
2926 PCB
->GridOffsetY
= GetValue (argv
[2], NULL
, NULL
);
2927 if (Settings
.DrawGrid
)
2944 /* --------------------------------------------------------------------------- */
2946 static const char mode_syntax
[] =
2947 N_("Mode(Arc|Arrow|Copy|InsertPoint|Line|Lock|Move|None|PasteBuffer)\n"
2948 "Mode(Polygon|Rectangle|Remove|Rotate|Text|Thermal|Via)\n"
2949 "Mode(Notify|Release|Cancel|Stroke)\n"
2950 "Mode(Save|Restore)");
2952 static const char mode_help
[] = N_("Change or use the tool mode.");
2954 /* %start-doc actions Mode
2974 Select the indicated tool.
2977 Called when you press the mouse button, or move the mouse.
2980 Called when you release the mouse button.
2983 Cancels any pending tool activity, allowing you to restart elsewhere.
2984 For example, this allows you to start a new line rather than attach a
2985 line to the previous line.
2988 Similar to Cancel but calling this action a second time will return
2992 If your @code{pcb} was built with libstroke, this invokes the stroke
2993 input method. If not, this will restart a drawing mode if you were
2994 drawing, else it will select objects.
2997 Remembers the current tool.
3000 Restores the tool to the last saved tool.
3007 ActionMode (int argc
, char **argv
, Coord x
, Coord y
)
3009 char *function
= ARG (0);
3013 Note
.X
= Crosshair
.X
;
3014 Note
.Y
= Crosshair
.Y
;
3015 notify_crosshair_change (false);
3016 switch (GetFunctionID (function
))
3022 SetMode (ARROW_MODE
);
3025 SetMode (COPY_MODE
);
3028 SetMode (INSERTPOINT_MODE
);
3031 SetMode (LINE_MODE
);
3034 SetMode (LOCK_MODE
);
3037 SetMode (MOVE_MODE
);
3044 int saved_mode
= Settings
.Mode
;
3046 SetMode (saved_mode
);
3051 switch (Settings
.Mode
)
3054 case PASTEBUFFER_MODE
:
3060 case INSERTPOINT_MODE
:
3061 case RUBBERBANDMOVE_MODE
:
3065 SetMode (ARROW_MODE
);
3069 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3070 SetMode (ARROW_MODE
);
3074 SetMode (LINE_MODE
);
3078 case RECTANGLE_MODE
:
3079 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3080 SetMode (ARROW_MODE
);
3084 SetMode (RECTANGLE_MODE
);
3089 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3090 SetMode (ARROW_MODE
);
3094 SetMode (POLYGON_MODE
);
3098 case POLYGONHOLE_MODE
:
3099 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3100 SetMode (ARROW_MODE
);
3104 SetMode (POLYGONHOLE_MODE
);
3109 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3110 SetMode (ARROW_MODE
);
3131 SetMode (PASTEBUFFER_MODE
);
3134 SetMode (POLYGON_MODE
);
3137 SetMode (POLYGONHOLE_MODE
);
3139 #ifndef HAVE_LIBSTROKE
3152 SetMode (REMOVE_MODE
);
3155 SetMode (RECTANGLE_MODE
);
3158 SetMode (ROTATE_MODE
);
3161 #ifdef HAVE_LIBSTROKE
3163 StrokeBox
.X1
= Crosshair
.X
;
3164 StrokeBox
.Y1
= Crosshair
.Y
;
3167 /* Handle middle mouse button restarts of drawing mode. If not in
3168 | a drawing mode, middle mouse button will select objects.
3170 if (Settings
.Mode
== LINE_MODE
3171 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3173 SetMode (LINE_MODE
);
3175 else if (Settings
.Mode
== ARC_MODE
3176 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3178 else if (Settings
.Mode
== RECTANGLE_MODE
3179 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3180 SetMode (RECTANGLE_MODE
);
3181 else if (Settings
.Mode
== POLYGON_MODE
3182 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3183 SetMode (POLYGON_MODE
);
3188 SetMode (ARROW_MODE
);
3194 SetMode (TEXT_MODE
);
3197 SetMode (THERMAL_MODE
);
3203 case F_Restore
: /* restore the last saved mode */
3207 case F_Save
: /* save currently selected mode */
3211 notify_crosshair_change (true);
3218 /* --------------------------------------------------------------------------- */
3220 static const char removeselected_syntax
[] = N_("RemoveSelected()");
3222 static const char removeselected_help
[] = N_("Removes any selected objects.");
3224 /* %start-doc actions RemoveSelected
3229 ActionRemoveSelected (int argc
, char **argv
, Coord x
, Coord y
)
3231 if (RemoveSelected ())
3232 SetChangedFlag (true);
3236 /* --------------------------------------------------------------------------- */
3238 static const char renumber_syntax
[] = N_("Renumber()\n"
3239 "Renumber(filename)");
3241 static const char renumber_help
[] =
3242 N_("Renumber all elements. The changes will be recorded to filename\n"
3243 "for use in backannotating these changes to the schematic.");
3245 /* %start-doc actions Renumber
3250 ActionRenumber (int argc
, char **argv
, Coord x
, Coord y
)
3252 bool changed
= false;
3253 ElementType
**element_list
;
3254 ElementType
**locked_element_list
;
3255 unsigned int i
, j
, k
, cnt
, lock_cnt
;
3261 static char * default_file
= NULL
;
3262 size_t cnt_list_sz
= 100;
3268 char **was
, **is
, *pin
;
3269 unsigned int c_cnt
= 0;
3276 * We deal with the case where name already exists in this
3277 * function so the GUI doesn't need to deal with it
3279 name
= gui
->fileselect (_("Save Renumber Annotation File As ..."),
3280 _("Choose a file to record the renumbering to.\n"
3281 "This file may be used to back annotate the\n"
3282 "change to the schematics.\n"),
3283 default_file
, ".eco", "eco",
3293 free (default_file
);
3294 default_file
= NULL
;
3299 default_file
= strdup (name
);
3302 if ((out
= fopen (name
, "r")))
3305 if (!gui
->confirm_dialog (_("File exists! Ok to overwrite?"), 0))
3307 if (free_name
&& name
)
3313 if ((out
= fopen (name
, "w")) == NULL
)
3315 Message (_("Could not open %s\n"), name
);
3316 if (free_name
&& name
)
3321 if (free_name
&& name
)
3324 fprintf (out
, "*COMMENT* PCB Annotation File\n");
3325 fprintf (out
, "*FILEVERSION* 20061031\n");
3328 * Make a first pass through all of the elements and sort them out
3329 * by location on the board. While here we also collect a list of
3332 * We'll actually renumber things in the 2nd pass.
3334 element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementType
*));
3335 locked_element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementType
*));
3336 was
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3337 is
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3338 if (element_list
== NULL
|| locked_element_list
== NULL
|| was
== NULL
3341 fprintf (stderr
, "calloc() failed in %s\n", __FUNCTION__
);
3348 ELEMENT_LOOP (PCB
->Data
);
3350 if (TEST_FLAG (LOCKFLAG
, element
->Name
) || TEST_FLAG (LOCKFLAG
, element
))
3353 * add to the list of locked elements which we won't try to
3354 * renumber and whose reference designators are now reserved.
3357 "*WARN* Element \"%s\" at %$md is locked and will not be renumbered.\n",
3358 UNKNOWN (NAMEONPCB_NAME (element
)), element
->MarkX
, element
->MarkY
);
3359 locked_element_list
[lock_cnt
] = element
;
3365 /* count of devices which will be renumbered */
3368 /* search for correct position in the list */
3370 while (element_list
[i
] && element
->MarkY
> element_list
[i
]->MarkY
)
3374 * We have found the position where we have the first element that
3375 * has the same Y value or a lower Y value. Now move forward if
3376 * needed through the X values
3378 while (element_list
[i
]
3379 && element
->MarkY
== element_list
[i
]->MarkY
3380 && element
->MarkX
> element_list
[i
]->MarkX
)
3383 for (j
= cnt
- 1; j
> i
; j
--)
3385 element_list
[j
] = element_list
[j
- 1];
3387 element_list
[i
] = element
;
3394 * Now that the elements are sorted by board position, we go through
3395 * and renumber them.
3399 * turn off the flag which requires unique names so it doesn't get
3400 * in our way. When we're done with the renumber we will have unique
3403 unique
= TEST_FLAG (UNIQUENAMEFLAG
, PCB
);
3404 CLEAR_FLAG (UNIQUENAMEFLAG
, PCB
);
3406 cnt_list
= (struct _cnt_list
*)calloc (cnt_list_sz
, sizeof (struct _cnt_list
));
3407 for (i
= 0; i
< cnt
; i
++)
3409 /* If there is no refdes, maybe just spit out a warning */
3410 if (NAMEONPCB_NAME (element_list
[i
]))
3412 /* figure out the prefix */
3413 tmps
= strdup (NAMEONPCB_NAME (element_list
[i
]));
3415 while (tmps
[j
] && (tmps
[j
] < '0' || tmps
[j
] > '9')
3420 /* check the counter for this prefix */
3422 cnt_list
[j
].name
&& (strcmp (cnt_list
[j
].name
, tmps
) != 0)
3423 && j
< cnt_list_sz
; j
++);
3425 /* grow the list if needed */
3426 if (j
== cnt_list_sz
)
3429 cnt_list
= (struct _cnt_list
*)realloc (cnt_list
, cnt_list_sz
);
3430 if (cnt_list
== NULL
)
3432 fprintf (stderr
, _("realloc failed() in %s\n"), __FUNCTION__
);
3435 /* zero out the memory that we added */
3436 for (tmpi
= j
; tmpi
< cnt_list_sz
; tmpi
++)
3438 cnt_list
[tmpi
].name
= NULL
;
3439 cnt_list
[tmpi
].cnt
= 0;
3444 * start a new counter if we don't have a counter for this
3447 if (!cnt_list
[j
].name
)
3449 cnt_list
[j
].name
= strdup (tmps
);
3450 cnt_list
[j
].cnt
= 0;
3454 * check to see if the new refdes is already used by a
3463 /* space for the prefix plus 1 digit plus the '\0' */
3464 sz
= strlen (cnt_list
[j
].name
) + 2;
3466 /* and 1 more per extra digit needed to hold the number */
3467 tmpi
= cnt_list
[j
].cnt
;
3473 tmps
= (char *)malloc (sz
* sizeof (char));
3474 sprintf (tmps
, "%s%d", cnt_list
[j
].name
, cnt_list
[j
].cnt
);
3477 * now compare to the list of reserved (by locked
3480 for (k
= 0; k
< lock_cnt
; k
++)
3483 (UNKNOWN (NAMEONPCB_NAME (locked_element_list
[k
])),
3494 if (strcmp (tmps
, NAMEONPCB_NAME (element_list
[i
])) != 0)
3496 fprintf (out
, "*RENAME* \"%s\" \"%s\"\n",
3497 NAMEONPCB_NAME (element_list
[i
]), tmps
);
3499 /* add this rename to our table of renames so we can update the netlist */
3500 was
[c_cnt
] = strdup (NAMEONPCB_NAME (element_list
[i
]));
3501 is
[c_cnt
] = strdup (tmps
);
3504 AddObjectToChangeNameUndoList (ELEMENT_TYPE
, NULL
, NULL
,
3506 NAMEONPCB_NAME (element_list
3509 ChangeObjectName (ELEMENT_TYPE
, element_list
[i
], NULL
, NULL
,
3513 /* we don't free tmps in this case because it is used */
3520 pcb_fprintf (out
, "*WARN* Element at %$md has no name.\n",
3521 element_list
[i
]->MarkX
, element_list
[i
]->MarkY
);
3528 /* restore the unique flag setting */
3530 SET_FLAG (UNIQUENAMEFLAG
, PCB
);
3535 /* update the netlist */
3536 AddNetlistLibToUndoList (&(PCB
->NetlistLib
));
3538 /* iterate over each net */
3539 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
3542 /* iterate over each pin on the net */
3543 for (j
= 0; j
< PCB
->NetlistLib
.Menu
[i
].EntryN
; j
++)
3546 /* figure out the pin number part from strings like U3-21 */
3547 tmps
= strdup (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3548 for (k
= 0; tmps
[k
] && tmps
[k
] != '-'; k
++);
3552 /* iterate over the list of changed reference designators */
3553 for (k
= 0; k
< c_cnt
; k
++)
3556 * if the pin needs to change, change it and quit
3557 * searching in the list.
3559 if (strcmp (tmps
, was
[k
]) == 0)
3561 free (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3562 PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
=
3563 (char *)malloc ((strlen (is
[k
]) + strlen (pin
) +
3564 2) * sizeof (char));
3565 sprintf (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
,
3566 "%s-%s", is
[k
], pin
);
3574 for (k
= 0; k
< c_cnt
; k
++)
3581 IncrementUndoSerialNumber ();
3582 SetChangedFlag (true);
3585 free (locked_element_list
);
3586 free (element_list
);
3592 /* --------------------------------------------------------------------------- */
3594 static const char ripup_syntax
[] = N_("RipUp(All|Selected|Element)");
3596 static const char ripup_help
[] =
3597 N_("Ripup auto-routed tracks, or convert an element to parts.");
3599 /* %start-doc actions RipUp
3604 Removes all lines and vias which were created by the autorouter.
3607 Removes all selected lines and vias which were created by the
3611 Converts the element under the cursor to parts (vias and lines). Note
3612 that this uses the highest numbered paste buffer.
3619 ActionRipUp (int argc
, char **argv
, Coord x
, Coord y
)
3621 char *function
= ARG (0);
3622 bool changed
= false;
3626 switch (GetFunctionID (function
))
3629 ALLLINE_LOOP (PCB
->Data
);
3631 if (TEST_FLAG (AUTOFLAG
, line
) && !TEST_FLAG (LOCKFLAG
, line
))
3633 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3638 ALLARC_LOOP (PCB
->Data
);
3640 if (TEST_FLAG (AUTOFLAG
, arc
) && !TEST_FLAG (LOCKFLAG
, arc
))
3642 RemoveObject (ARC_TYPE
, layer
, arc
, arc
);
3647 VIA_LOOP (PCB
->Data
);
3649 if (TEST_FLAG (AUTOFLAG
, via
) && !TEST_FLAG (LOCKFLAG
, via
))
3651 RemoveObject (VIA_TYPE
, via
, via
, via
);
3659 IncrementUndoSerialNumber ();
3660 SetChangedFlag (true);
3664 VISIBLELINE_LOOP (PCB
->Data
);
3666 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, line
)
3667 && !TEST_FLAG (LOCKFLAG
, line
))
3669 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3675 VIA_LOOP (PCB
->Data
);
3677 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, via
)
3678 && !TEST_FLAG (LOCKFLAG
, via
))
3680 RemoveObject (VIA_TYPE
, via
, via
, via
);
3687 IncrementUndoSerialNumber ();
3688 SetChangedFlag (true);
3693 void *ptr1
, *ptr2
, *ptr3
;
3695 if (SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
3696 &ptr1
, &ptr2
, &ptr3
) != NO_TYPE
)
3698 Note
.Buffer
= Settings
.BufferNumber
;
3699 SetBufferNumber (MAX_BUFFER
- 1);
3700 ClearBuffer (PASTEBUFFER
);
3701 CopyObjectToBuffer (PASTEBUFFER
->Data
, PCB
->Data
,
3702 ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3703 SmashBufferElement (PASTEBUFFER
);
3706 SaveUndoSerialNumber ();
3707 EraseObject (ELEMENT_TYPE
, ptr1
, ptr1
);
3708 MoveObjectToRemoveUndoList (ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3709 RestoreUndoSerialNumber ();
3710 CopyPastebufferToLayout (0, 0);
3711 SetBufferNumber (Note
.Buffer
);
3712 SetChangedFlag (true);
3721 /* --------------------------------------------------------------------------- */
3723 static const char addrats_syntax
[] = N_("AddRats(AllRats|SelectedRats|Close)");
3725 static const char addrats_help
[] =
3726 N_("Add one or more rat lines to the board.");
3728 /* %start-doc actions AddRats
3733 Create rat lines for all loaded nets that aren't already connected on
3737 Similarly, but only add rat lines for nets connected to selected pins
3741 Selects the shortest unselected rat on the board.
3748 ActionAddRats (int argc
, char **argv
, Coord x
, Coord y
)
3750 char *function
= ARG (0);
3756 if (Settings
.RatWarn
)
3758 switch (GetFunctionID (function
))
3761 if (AddAllRats (false, NULL
))
3762 SetChangedFlag (true);
3764 case F_SelectedRats
:
3766 if (AddAllRats (true, NULL
))
3767 SetChangedFlag (true);
3770 small
= SQUARE (MAX_COORD
);
3772 RAT_LOOP (PCB
->Data
);
3774 if (TEST_FLAG (SELECTEDFLAG
, line
))
3776 len
= SQUARE (line
->Point1
.X
- line
->Point2
.X
) +
3777 SQUARE (line
->Point1
.Y
- line
->Point2
.Y
);
3787 AddObjectToFlagUndoList (RATLINE_TYPE
, shorty
, shorty
, shorty
);
3788 SET_FLAG (SELECTEDFLAG
, shorty
);
3791 CenterDisplay ((shorty
->Point2
.X
+ shorty
->Point1
.X
) / 2,
3792 (shorty
->Point2
.Y
+ shorty
->Point1
.Y
) / 2);
3800 /* --------------------------------------------------------------------------- */
3802 static const char delete_syntax
[] =
3803 N_("Delete(Object|Selected)\n"
3804 "Delete(AllRats|SelectedRats)");
3806 static const char delete_help
[] = N_("Delete stuff.");
3808 /* %start-doc actions Delete
3813 ActionDelete (int argc
, char **argv
, Coord x
, Coord y
)
3815 char *function
= ARG (0);
3816 int id
= GetFunctionID (function
);
3818 Note
.X
= Crosshair
.X
;
3819 Note
.Y
= Crosshair
.Y
;
3821 if (id
== -1) /* no arg */
3823 if (RemoveSelected() == false)
3831 SetMode(REMOVE_MODE
);
3839 if (DeleteRats (false))
3840 SetChangedFlag (true);
3842 case F_SelectedRats
:
3843 if (DeleteRats (true))
3844 SetChangedFlag (true);
3851 /* --------------------------------------------------------------------------- */
3853 static const char deleterats_syntax
[] =
3854 N_("DeleteRats(AllRats|Selected|SelectedRats)");
3856 static const char deleterats_help
[] = N_("Delete rat lines.");
3858 /* %start-doc actions DeleteRats
3863 ActionDeleteRats (int argc
, char **argv
, Coord x
, Coord y
)
3865 char *function
= ARG (0);
3868 if (Settings
.RatWarn
)
3870 switch (GetFunctionID (function
))
3873 if (DeleteRats (false))
3874 SetChangedFlag (true);
3876 case F_SelectedRats
:
3878 if (DeleteRats (true))
3879 SetChangedFlag (true);
3886 /* --------------------------------------------------------------------------- */
3888 static const char autoplace_syntax
[] = N_("AutoPlaceSelected()");
3890 static const char autoplace_help
[] = N_("Auto-place selected components.");
3892 /* %start-doc actions AutoPlaceSelected
3894 Attempts to re-arrange the selected components such that the nets
3895 connecting them are minimized. Note that you cannot undo this.
3900 ActionAutoPlaceSelected (int argc
, char **argv
, Coord x
, Coord y
)
3903 if (gui
->confirm_dialog (_("Auto-placement can NOT be undone.\n"
3904 "Do you want to continue anyway?\n"), 0))
3906 if (AutoPlaceSelected ())
3907 SetChangedFlag (true);
3912 /* --------------------------------------------------------------------------- */
3914 static const char autoroute_syntax
[] = N_("AutoRoute(AllRats|SelectedRats)");
3916 static const char autoroute_help
[] = N_("Auto-route some or all rat lines.");
3918 /* %start-doc actions AutoRoute
3923 Attempt to autoroute all rats.
3926 Attempt to autoroute the selected rats.
3930 Before autorouting, it's important to set up a few things. First,
3931 make sure any layers you aren't using are disabled, else the
3932 autorouter may use them. Next, make sure the current line and via
3933 styles are set accordingly. Last, make sure "new lines clear
3934 polygons" is set, in case you eventually want to add a copper pour.
3936 Autorouting takes a while. During this time, the program may not be
3942 ActionAutoRoute (int argc
, char **argv
, Coord x
, Coord y
)
3944 char *function
= ARG (0);
3946 if (function
) /* one parameter */
3948 switch (GetFunctionID (function
))
3951 if (AutoRoute (false))
3952 SetChangedFlag (true);
3954 case F_SelectedRats
:
3956 if (AutoRoute (true))
3957 SetChangedFlag (true);
3964 /* --------------------------------------------------------------------------- */
3966 static const char markcrosshair_syntax
[] =
3967 N_("MarkCrosshair()\n"
3968 "MarkCrosshair(Center)");
3970 static const char markcrosshair_help
[] = N_("Set/Reset the Crosshair mark.");
3972 /* %start-doc actions MarkCrosshair
3974 The ``mark'' is a small X-shaped target on the display which is
3975 treated like a second origin (the normal origin is the upper let
3976 corner of the board). The GUI will display a second set of
3977 coordinates for this mark, which tells you how far you are from it.
3979 If no argument is given, the mark is toggled - disabled if it was
3980 enabled, or enabled at the current cursor position of disabled. If
3981 the @code{Center} argument is given, the mark is moved to the current
3987 ActionMarkCrosshair (int argc
, char **argv
, Coord x
, Coord y
)
3989 char *function
= ARG (0);
3990 if (!function
|| !*function
)
3994 notify_mark_change (false);
3995 Marked
.status
= false;
3996 notify_mark_change (true);
4000 notify_mark_change (false);
4001 Marked
.status
= false;
4002 Marked
.status
= true;
4003 Marked
.X
= Crosshair
.X
;
4004 Marked
.Y
= Crosshair
.Y
;
4005 notify_mark_change (true);
4008 else if (GetFunctionID (function
) == F_Center
)
4010 notify_mark_change (false);
4011 Marked
.status
= true;
4012 Marked
.X
= Crosshair
.X
;
4013 Marked
.Y
= Crosshair
.Y
;
4014 notify_mark_change (true);
4019 /* --------------------------------------------------------------------------- */
4021 static const char changesize_syntax
[] =
4022 N_("ChangeSize(Object, delta)\n"
4023 "ChangeSize(SelectedObjects|Selected, delta)\n"
4024 "ChangeSize(SelectedLines|SelectedPins|SelectedVias, delta)\n"
4025 "ChangeSize(SelectedPads|SelectedTexts|SelectedNames, delta)\n"
4026 "ChangeSize(SelectedElements, delta)");
4028 static const char changesize_help
[] = N_("Changes the size of objects.");
4030 /* %start-doc actions ChangeSize
4032 For lines and arcs, this changes the width. For pins and vias, this
4033 changes the overall diameter of the copper annulus. For pads, this
4034 changes the width and, indirectly, the length. For texts and names,
4035 this changes the scaling factor. For elements, this changes the width
4036 of the silk layer lines and arcs for this element.
4041 ActionChangeSize (int argc
, char **argv
, Coord x
, Coord y
)
4043 char *function
= ARG (0);
4044 char *delta
= ARG (1);
4045 char *units
= ARG (2);
4046 bool absolute
; /* indicates if absolute size is given */
4049 if (function
&& delta
)
4051 value
= GetValue (delta
, units
, &absolute
);
4053 value
= delta
[0] == '-' ? -Settings
.increments
->size
4054 : Settings
.increments
->size
;
4055 switch (GetFunctionID (function
))
4060 void *ptr1
, *ptr2
, *ptr3
;
4063 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
4064 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4065 if (TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
4066 Message (_("Sorry, the object is locked\n"));
4067 if (ChangeObjectSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4068 SetChangedFlag (true);
4072 case F_SelectedVias
:
4073 if (ChangeSelectedSize (VIA_TYPE
, value
, absolute
))
4074 SetChangedFlag (true);
4077 case F_SelectedPins
:
4078 if (ChangeSelectedSize (PIN_TYPE
, value
, absolute
))
4079 SetChangedFlag (true);
4082 case F_SelectedPads
:
4083 if (ChangeSelectedSize (PAD_TYPE
, value
, absolute
))
4084 SetChangedFlag (true);
4087 case F_SelectedArcs
:
4088 if (ChangeSelectedSize (ARC_TYPE
, value
, absolute
))
4089 SetChangedFlag (true);
4092 case F_SelectedLines
:
4093 if (ChangeSelectedSize (LINE_TYPE
, value
, absolute
))
4094 SetChangedFlag (true);
4097 case F_SelectedTexts
:
4098 if (ChangeSelectedSize (TEXT_TYPE
, value
, absolute
))
4099 SetChangedFlag (true);
4102 case F_SelectedNames
:
4103 if (ChangeSelectedSize (ELEMENTNAME_TYPE
, value
, absolute
))
4104 SetChangedFlag (true);
4107 case F_SelectedElements
:
4108 if (ChangeSelectedSize (ELEMENT_TYPE
, value
, absolute
))
4109 SetChangedFlag (true);
4113 case F_SelectedObjects
:
4114 if (ChangeSelectedSize (CHANGESIZE_TYPES
, value
, absolute
))
4115 SetChangedFlag (true);
4122 /* --------------------------------------------------------------------------- */
4124 static const char changedrillsize_syntax
[] =
4125 N_("ChangeDrillSize(Object, delta)\n"
4126 "ChangeDrillSize(SelectedPins|SelectedVias|Selected|SelectedObjects, delta)");
4128 static const char changedrillsize_help
[] =
4129 N_("Changes the drilling hole size of objects.");
4131 /* %start-doc actions ChangeDrillSize
4136 ActionChange2ndSize (int argc
, char **argv
, Coord x
, Coord y
)
4138 char *function
= ARG (0);
4139 char *delta
= ARG (1);
4140 char *units
= ARG (2);
4144 if (function
&& delta
)
4146 value
= GetValue (delta
, units
, &absolute
);
4147 switch (GetFunctionID (function
))
4152 void *ptr1
, *ptr2
, *ptr3
;
4154 gui
->get_coords (_("Select an Object"), &x
, &y
);
4156 SearchScreen (x
, y
, CHANGE2NDSIZE_TYPES
,
4157 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4158 if (ChangeObject2ndSize
4159 (type
, ptr1
, ptr2
, ptr3
, value
, absolute
, true))
4160 SetChangedFlag (true);
4164 case F_SelectedVias
:
4165 if (ChangeSelected2ndSize (VIA_TYPE
, value
, absolute
))
4166 SetChangedFlag (true);
4169 case F_SelectedPins
:
4170 if (ChangeSelected2ndSize (PIN_TYPE
, value
, absolute
))
4171 SetChangedFlag (true);
4174 case F_SelectedObjects
:
4175 if (ChangeSelected2ndSize (PIN_TYPES
, value
, absolute
))
4176 SetChangedFlag (true);
4183 /* --------------------------------------------------------------------------- */
4185 static const char changeclearsize_syntax
[] =
4186 N_("ChangeClearSize(Object, delta)\n"
4187 "ChangeClearSize(SelectedPins|SelectedPads|SelectedVias, delta)\n"
4188 "ChangeClearSize(SelectedLines|SelectedArcs, delta\n"
4189 "ChangeClearSize(Selected|SelectedObjects, delta)");
4191 static const char changeclearsize_help
[] =
4192 N_("Changes the clearance size of objects.");
4194 /* %start-doc actions ChangeClearSize
4196 If the solder mask is currently showing, this action changes the
4197 solder mask clearance. If the mask is not showing, this action
4198 changes the polygon clearance.
4203 ActionChangeClearSize (int argc
, char **argv
, Coord x
, Coord y
)
4205 char *function
= ARG (0);
4206 char *delta
= ARG (1);
4207 char *units
= ARG (2);
4211 if (function
&& delta
)
4213 value
= 2 * GetValue (delta
, units
, &absolute
);
4215 value
= delta
[0] == '-' ? -Settings
.increments
->clear
4216 : Settings
.increments
->clear
;
4217 switch (GetFunctionID (function
))
4222 void *ptr1
, *ptr2
, *ptr3
;
4224 gui
->get_coords (_("Select an Object"), &x
, &y
);
4227 CHANGECLEARSIZE_TYPES
, &ptr1
, &ptr2
,
4229 if (ChangeObjectClearSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4230 SetChangedFlag (true);
4233 case F_SelectedVias
:
4234 if (ChangeSelectedClearSize (VIA_TYPE
, value
, absolute
))
4235 SetChangedFlag (true);
4237 case F_SelectedPads
:
4238 if (ChangeSelectedClearSize (PAD_TYPE
, value
, absolute
))
4239 SetChangedFlag (true);
4241 case F_SelectedPins
:
4242 if (ChangeSelectedClearSize (PIN_TYPE
, value
, absolute
))
4243 SetChangedFlag (true);
4245 case F_SelectedLines
:
4246 if (ChangeSelectedClearSize (LINE_TYPE
, value
, absolute
))
4247 SetChangedFlag (true);
4249 case F_SelectedArcs
:
4250 if (ChangeSelectedClearSize (ARC_TYPE
, value
, absolute
))
4251 SetChangedFlag (true);
4254 case F_SelectedObjects
:
4255 if (ChangeSelectedClearSize (CHANGECLEARSIZE_TYPES
, value
, absolute
))
4256 SetChangedFlag (true);
4263 /* --------------------------------------------------------------------------- */
4265 static const char minmaskgap_syntax
[] =
4266 N_("MinMaskGap(delta)\n"
4267 "MinMaskGap(Selected, delta)");
4269 static const char minmaskgap_help
[] =
4270 N_("Ensures the mask is a minimum distance from pins and pads.");
4272 /* %start-doc actions MinMaskGap
4274 Checks all specified pins and/or pads, and increases the mask if
4275 needed to ensure a minimum distance between the pin or pad edge and
4281 ActionMinMaskGap (int argc
, char **argv
, Coord x
, Coord y
)
4283 char *function
= ARG (0);
4284 char *delta
= ARG (1);
4285 char *units
= ARG (2);
4292 if (strcasecmp (function
, "Selected") == 0)
4293 flags
= SELECTEDFLAG
;
4300 value
= 2 * GetValue (delta
, units
, &absolute
);
4302 SaveUndoSerialNumber ();
4303 ELEMENT_LOOP (PCB
->Data
);
4307 if (!TEST_FLAGS (flags
, pin
))
4309 if (pin
->Mask
< pin
->Thickness
+ value
)
4311 ChangeObjectMaskSize (PIN_TYPE
, element
, pin
, 0,
4312 pin
->Thickness
+ value
, 1);
4313 RestoreUndoSerialNumber ();
4319 if (!TEST_FLAGS (flags
, pad
))
4321 if (pad
->Mask
< pad
->Thickness
+ value
)
4323 ChangeObjectMaskSize (PAD_TYPE
, element
, pad
, 0,
4324 pad
->Thickness
+ value
, 1);
4325 RestoreUndoSerialNumber ();
4331 VIA_LOOP (PCB
->Data
);
4333 if (!TEST_FLAGS (flags
, via
))
4335 if (via
->Mask
&& via
->Mask
< via
->Thickness
+ value
)
4337 ChangeObjectMaskSize (VIA_TYPE
, via
, 0, 0, via
->Thickness
+ value
, 1);
4338 RestoreUndoSerialNumber ();
4342 RestoreUndoSerialNumber ();
4343 IncrementUndoSerialNumber ();
4347 /* --------------------------------------------------------------------------- */
4349 static const char mincleargap_syntax
[] =
4350 N_("MinClearGap(delta)\n"
4351 "MinClearGap(Selected, delta)");
4353 static const char mincleargap_help
[] =
4354 N_("Ensures that polygons are a minimum distance from objects.");
4356 /* %start-doc actions MinClearGap
4358 Checks all specified objects, and increases the polygon clearance if
4359 needed to ensure a minimum distance between their edges and the
4365 ActionMinClearGap (int argc
, char **argv
, Coord x
, Coord y
)
4367 char *function
= ARG (0);
4368 char *delta
= ARG (1);
4369 char *units
= ARG (2);
4376 if (strcasecmp (function
, "Selected") == 0)
4377 flags
= SELECTEDFLAG
;
4384 value
= 2 * GetValue (delta
, units
, &absolute
);
4386 SaveUndoSerialNumber ();
4387 ELEMENT_LOOP (PCB
->Data
);
4391 if (!TEST_FLAGS (flags
, pin
))
4393 if (pin
->Clearance
< value
)
4395 ChangeObjectClearSize (PIN_TYPE
, element
, pin
, 0,
4397 RestoreUndoSerialNumber ();
4403 if (!TEST_FLAGS (flags
, pad
))
4405 if (pad
->Clearance
< value
)
4407 ChangeObjectClearSize (PAD_TYPE
, element
, pad
, 0,
4409 RestoreUndoSerialNumber ();
4415 VIA_LOOP (PCB
->Data
);
4417 if (!TEST_FLAGS (flags
, via
))
4419 if (via
->Clearance
< value
)
4421 ChangeObjectClearSize (VIA_TYPE
, via
, 0, 0, value
, 1);
4422 RestoreUndoSerialNumber ();
4426 ALLLINE_LOOP (PCB
->Data
);
4428 if (!TEST_FLAGS (flags
, line
))
4430 if (line
->Clearance
< value
)
4432 ChangeObjectClearSize (LINE_TYPE
, layer
, line
, 0, value
, 1);
4433 RestoreUndoSerialNumber ();
4437 ALLARC_LOOP (PCB
->Data
);
4439 if (!TEST_FLAGS (flags
, arc
))
4441 if (arc
->Clearance
< value
)
4443 ChangeObjectClearSize (ARC_TYPE
, layer
, arc
, 0, value
, 1);
4444 RestoreUndoSerialNumber ();
4448 RestoreUndoSerialNumber ();
4449 IncrementUndoSerialNumber ();
4453 /* --------------------------------------------------------------------------- */
4455 static const char changepinname_syntax
[] =
4456 N_("ChangePinName(ElementName,PinNumber,PinName)");
4458 static const char changepinname_help
[] =
4459 N_("Sets the name of a specific pin on a specific element.");
4461 /* %start-doc actions ChangePinName
4463 This can be especially useful for annotating pin names from a
4464 schematic to the layout without requiring knowledge of the pcb file
4468 ChangePinName(U3, 7, VCC)
4474 ActionChangePinName (int argc
, char **argv
, Coord x
, Coord y
)
4477 char *refdes
, *pinnum
, *pinname
;
4481 AFAIL (changepinname
);
4488 ELEMENT_LOOP (PCB
->Data
);
4490 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
4494 if (NSTRCMP (pinnum
, pin
->Number
) == 0)
4496 AddObjectToChangeNameUndoList (PIN_TYPE
, NULL
, NULL
,
4499 * Note: we can't free() pin->Name first because
4500 * it is used in the undo list
4502 pin
->Name
= strdup (pinname
);
4503 SetChangedFlag (true);
4511 if (NSTRCMP (pinnum
, pad
->Number
) == 0)
4513 AddObjectToChangeNameUndoList (PAD_TYPE
, NULL
, NULL
,
4516 * Note: we can't free() pad->Name first because
4517 * it is used in the undo list
4519 pad
->Name
= strdup (pinname
);
4520 SetChangedFlag (true);
4529 * done with our action so increment the undo # if we actually
4535 defer_needs_update
= 1;
4538 IncrementUndoSerialNumber ();
4539 gui
->invalidate_all ();
4546 /* --------------------------------------------------------------------------- */
4548 static const char changename_syntax
[] =
4549 N_("ChangeName(Object)\n"
4550 "ChangeName(Layout|Layer)");
4552 static const char changename_help
[] = N_("Sets the name of objects.");
4554 /* %start-doc actions ChangeName
4559 Changes the name of the element under the cursor.
4562 Changes the name of the layout. This is printed on the fab drawings.
4565 Changes the name of the currently active layer.
4572 ActionChangeName (int argc
, char **argv
, Coord x
, Coord y
)
4574 char *function
= ARG (0);
4579 switch (GetFunctionID (function
))
4581 /* change the name of an object */
4585 void *ptr1
, *ptr2
, *ptr3
;
4587 gui
->get_coords (_("Select an Object"), &x
, &y
);
4589 SearchScreen (x
, y
, CHANGENAME_TYPES
,
4590 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4592 SaveUndoSerialNumber ();
4593 if (QueryInputAndChangeObjectName (type
, ptr1
, ptr2
, ptr3
))
4595 SetChangedFlag (true);
4596 if (type
== ELEMENT_TYPE
)
4598 RubberbandType
*ptr
;
4601 RestoreUndoSerialNumber ();
4602 Crosshair
.AttachedObject
.RubberbandN
= 0;
4603 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
4604 ptr
= Crosshair
.AttachedObject
.Rubberband
;
4605 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
;
4609 EraseRat ((RatType
*) ptr
->Line
);
4610 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
4611 ptr
->Line
, ptr
->Line
,
4614 IncrementUndoSerialNumber ();
4622 /* change the layout's name */
4625 gui
->prompt_for (_("Enter the layout name:"), EMPTY (PCB
->Name
));
4626 /* NB: ChangeLayoutName takes ownership of the passed memory */
4627 if (name
&& ChangeLayoutName (name
))
4628 SetChangedFlag (true);
4631 /* change the name of the active layer */
4633 name
= gui
->prompt_for (_("Enter the layer name:"),
4634 EMPTY (CURRENT
->Name
));
4635 /* NB: ChangeLayerName takes ownership of the passed memory */
4636 if (name
&& ChangeLayerName (CURRENT
, name
))
4637 SetChangedFlag (true);
4645 /* --------------------------------------------------------------------------- */
4647 static const char morphpolygon_syntax
[] = N_("MorphPolygon(Object|Selected)");
4649 static const char morphpolygon_help
[] =
4650 N_("Converts dead polygon islands into separate polygons.");
4652 /* %start-doc actions MorphPolygon
4654 If a polygon is divided into unconnected "islands", you can use
4655 this command to convert the otherwise disappeared islands into
4656 separate polygons. Be sure the cursor is over a portion of the
4657 polygon that remains visible. Very small islands that may flake
4658 off are automatically deleted.
4663 ActionMorphPolygon (int argc
, char **argv
, Coord x
, Coord y
)
4665 char *function
= ARG (0);
4668 switch (GetFunctionID (function
))
4673 void *ptr1
, *ptr2
, *ptr3
;
4675 gui
->get_coords (_("Select an Object"), &x
, &y
);
4676 if ((type
= SearchScreen (x
, y
, POLYGON_TYPE
,
4677 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4679 MorphPolygon ((LayerType
*) ptr1
, (PolygonType
*) ptr3
);
4681 IncrementUndoSerialNumber ();
4686 case F_SelectedObjects
:
4687 ALLPOLYGON_LOOP (PCB
->Data
);
4689 if (TEST_FLAG (SELECTEDFLAG
, polygon
))
4690 MorphPolygon (layer
, polygon
);
4694 IncrementUndoSerialNumber ();
4701 /* --------------------------------------------------------------------------- */
4703 static const char togglehidename_syntax
[] =
4704 N_("ToggleHideName(Object|SelectedElements)");
4706 static const char togglehidename_help
[] =
4707 N_("Toggles the visibility of element names.");
4709 /* %start-doc actions ToggleHideName
4711 If names are hidden you won't see them on the screen and they will not
4712 appear on the silk layer when you print the layout.
4717 ActionToggleHideName (int argc
, char **argv
, Coord x
, Coord y
)
4719 char *function
= ARG (0);
4720 if (function
&& PCB
->ElementOn
)
4722 switch (GetFunctionID (function
))
4727 void *ptr1
, *ptr2
, *ptr3
;
4729 gui
->get_coords (_("Select an Object"), &x
, &y
);
4730 if ((type
= SearchScreen (x
, y
, ELEMENT_TYPE
,
4731 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4733 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr3
);
4734 EraseElementName ((ElementType
*) ptr2
);
4735 TOGGLE_FLAG (HIDENAMEFLAG
, (ElementType
*) ptr2
);
4736 DrawElementName ((ElementType
*) ptr2
);
4738 IncrementUndoSerialNumber ();
4742 case F_SelectedElements
:
4745 bool changed
= false;
4746 ELEMENT_LOOP (PCB
->Data
);
4748 if ((TEST_FLAG (SELECTEDFLAG
, element
) ||
4749 TEST_FLAG (SELECTEDFLAG
,
4750 &NAMEONPCB_TEXT (element
)))
4751 && (FRONT (element
) || PCB
->InvisibleObjectsOn
))
4753 AddObjectToFlagUndoList (ELEMENT_TYPE
, element
,
4755 EraseElementName (element
);
4756 TOGGLE_FLAG (HIDENAMEFLAG
, element
);
4757 DrawElementName (element
);
4765 IncrementUndoSerialNumber ();
4773 /* --------------------------------------------------------------------------- */
4775 static const char changejoin_syntax
[] =
4776 N_("ChangeJoin(ToggleObject|SelectedLines|SelectedArcs|Selected)");
4778 static const char changejoin_help
[] =
4779 N_("Changes the join (clearance through polygons) of objects.");
4781 /* %start-doc actions ChangeJoin
4783 The join flag determines whether a line or arc, drawn to intersect a
4784 polygon, electrically connects to the polygon or not. When joined,
4785 the line/arc is simply drawn over the polygon, making an electrical
4786 connection. When not joined, a gap is drawn between the line and the
4787 polygon, insulating them from each other.
4792 ActionChangeJoin (int argc
, char **argv
, Coord x
, Coord y
)
4794 char *function
= ARG (0);
4797 switch (GetFunctionID (function
))
4799 case F_ToggleObject
:
4803 void *ptr1
, *ptr2
, *ptr3
;
4805 gui
->get_coords (_("Select an Object"), &x
, &y
);
4807 SearchScreen (x
, y
, CHANGEJOIN_TYPES
,
4808 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4809 if (ChangeObjectJoin (type
, ptr1
, ptr2
, ptr3
))
4810 SetChangedFlag (true);
4814 case F_SelectedLines
:
4815 if (ChangeSelectedJoin (LINE_TYPE
))
4816 SetChangedFlag (true);
4819 case F_SelectedArcs
:
4820 if (ChangeSelectedJoin (ARC_TYPE
))
4821 SetChangedFlag (true);
4825 case F_SelectedObjects
:
4826 if (ChangeSelectedJoin (CHANGEJOIN_TYPES
))
4827 SetChangedFlag (true);
4834 /* --------------------------------------------------------------------------- */
4836 static const char changesquare_syntax
[] =
4837 N_("ChangeSquare(ToggleObject)\n"
4838 "ChangeSquare(SelectedElements|SelectedPins)\n"
4839 "ChangeSquare(Selected|SelectedObjects)");
4841 static const char changesquare_help
[] =
4842 N_("Changes the square flag of pins and pads.");
4844 /* %start-doc actions ChangeSquare
4846 Note that @code{Pins} means both pins and pads.
4853 ActionChangeSquare (int argc
, char **argv
, Coord x
, Coord y
)
4855 char *function
= ARG (0);
4858 switch (GetFunctionID (function
))
4860 case F_ToggleObject
:
4864 void *ptr1
, *ptr2
, *ptr3
;
4866 gui
->get_coords (_("Select an Object"), &x
, &y
);
4868 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4869 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4870 if (ChangeObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4871 SetChangedFlag (true);
4875 case F_SelectedElements
:
4876 if (ChangeSelectedSquare (ELEMENT_TYPE
))
4877 SetChangedFlag (true);
4880 case F_SelectedPins
:
4881 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4882 SetChangedFlag (true);
4886 case F_SelectedObjects
:
4887 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4888 SetChangedFlag (true);
4895 /* --------------------------------------------------------------------------- */
4897 static const char setsquare_syntax
[] =
4898 N_("SetSquare(ToggleObject|SelectedElements|SelectedPins)");
4900 static const char setsquare_help
[] = N_("sets the square-flag of objects.");
4902 /* %start-doc actions SetSquare
4904 Note that @code{Pins} means pins and pads.
4911 ActionSetSquare (int argc
, char **argv
, Coord x
, Coord y
)
4913 char *function
= ARG (0);
4914 if (function
&& *function
)
4916 switch (GetFunctionID (function
))
4918 case F_ToggleObject
:
4922 void *ptr1
, *ptr2
, *ptr3
;
4924 gui
->get_coords (_("Select an Object"), &x
, &y
);
4926 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4927 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4928 if (SetObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4929 SetChangedFlag (true);
4933 case F_SelectedElements
:
4934 if (SetSelectedSquare (ELEMENT_TYPE
))
4935 SetChangedFlag (true);
4938 case F_SelectedPins
:
4939 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4940 SetChangedFlag (true);
4944 case F_SelectedObjects
:
4945 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4946 SetChangedFlag (true);
4953 /* --------------------------------------------------------------------------- */
4955 static const char clearsquare_syntax
[] =
4956 N_("ClearSquare(ToggleObject|SelectedElements|SelectedPins)");
4958 static const char clearsquare_help
[] =
4959 N_("Clears the square-flag of pins and pads.");
4961 /* %start-doc actions ClearSquare
4963 Note that @code{Pins} means pins and pads.
4970 ActionClearSquare (int argc
, char **argv
, Coord x
, Coord y
)
4972 char *function
= ARG (0);
4973 if (function
&& *function
)
4975 switch (GetFunctionID (function
))
4977 case F_ToggleObject
:
4981 void *ptr1
, *ptr2
, *ptr3
;
4983 gui
->get_coords (_("Select an Object"), &x
, &y
);
4985 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4986 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4987 if (ClrObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4988 SetChangedFlag (true);
4992 case F_SelectedElements
:
4993 if (ClrSelectedSquare (ELEMENT_TYPE
))
4994 SetChangedFlag (true);
4997 case F_SelectedPins
:
4998 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4999 SetChangedFlag (true);
5003 case F_SelectedObjects
:
5004 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
5005 SetChangedFlag (true);
5012 /* --------------------------------------------------------------------------- */
5014 static const char changeoctagon_syntax
[] =
5015 N_("ChangeOctagon(Object|ToggleObject|SelectedObjects|Selected)\n"
5016 "ChangeOctagon(SelectedElements|SelectedPins|SelectedVias)");
5018 static const char changeoctagon_help
[] =
5019 N_("Changes the octagon-flag of pins and vias.");
5021 /* %start-doc actions ChangeOctagon
5028 ActionChangeOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5030 char *function
= ARG (0);
5033 switch (GetFunctionID (function
))
5035 case F_ToggleObject
:
5039 void *ptr1
, *ptr2
, *ptr3
;
5041 gui
->get_coords (_("Select an Object"), &x
, &y
);
5043 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5044 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5045 if (ChangeObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5046 SetChangedFlag (true);
5050 case F_SelectedElements
:
5051 if (ChangeSelectedOctagon (ELEMENT_TYPE
))
5052 SetChangedFlag (true);
5055 case F_SelectedPins
:
5056 if (ChangeSelectedOctagon (PIN_TYPE
))
5057 SetChangedFlag (true);
5060 case F_SelectedVias
:
5061 if (ChangeSelectedOctagon (VIA_TYPE
))
5062 SetChangedFlag (true);
5066 case F_SelectedObjects
:
5067 if (ChangeSelectedOctagon (PIN_TYPES
))
5068 SetChangedFlag (true);
5075 /* --------------------------------------------------------------------------- */
5077 static const char setoctagon_syntax
[] =
5078 N_("SetOctagon(Object|ToggleObject|SelectedElements|Selected)");
5080 static const char setoctagon_help
[] = N_("Sets the octagon-flag of objects.");
5082 /* %start-doc actions SetOctagon
5089 ActionSetOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5091 char *function
= ARG (0);
5094 switch (GetFunctionID (function
))
5096 case F_ToggleObject
:
5100 void *ptr1
, *ptr2
, *ptr3
;
5102 gui
->get_coords (_("Select an Object"), &x
, &y
);
5104 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5105 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5106 if (SetObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5107 SetChangedFlag (true);
5111 case F_SelectedElements
:
5112 if (SetSelectedOctagon (ELEMENT_TYPE
))
5113 SetChangedFlag (true);
5116 case F_SelectedPins
:
5117 if (SetSelectedOctagon (PIN_TYPE
))
5118 SetChangedFlag (true);
5121 case F_SelectedVias
:
5122 if (SetSelectedOctagon (VIA_TYPE
))
5123 SetChangedFlag (true);
5127 case F_SelectedObjects
:
5128 if (SetSelectedOctagon (PIN_TYPES
))
5129 SetChangedFlag (true);
5136 /* --------------------------------------------------------------------------- */
5138 static const char clearoctagon_syntax
[] =
5139 N_("ClearOctagon(ToggleObject|Object|SelectedObjects|Selected)\n"
5140 "ClearOctagon(SelectedElements|SelectedPins|SelectedVias)");
5142 static const char clearoctagon_help
[] =
5143 N_("Clears the octagon-flag of pins and vias.");
5145 /* %start-doc actions ClearOctagon
5152 ActionClearOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5154 char *function
= ARG (0);
5157 switch (GetFunctionID (function
))
5159 case F_ToggleObject
:
5163 void *ptr1
, *ptr2
, *ptr3
;
5165 gui
->get_coords (_("Select an Object"), &x
, &y
);
5167 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGEOCTAGON_TYPES
,
5168 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5169 if (ClrObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5170 SetChangedFlag (true);
5174 case F_SelectedElements
:
5175 if (ClrSelectedOctagon (ELEMENT_TYPE
))
5176 SetChangedFlag (true);
5179 case F_SelectedPins
:
5180 if (ClrSelectedOctagon (PIN_TYPE
))
5181 SetChangedFlag (true);
5184 case F_SelectedVias
:
5185 if (ClrSelectedOctagon (VIA_TYPE
))
5186 SetChangedFlag (true);
5190 case F_SelectedObjects
:
5191 if (ClrSelectedOctagon (PIN_TYPES
))
5192 SetChangedFlag (true);
5199 /* --------------------------------------------------------------------------- */
5201 static const char changehold_syntax
[] =
5202 N_("ChangeHole(ToggleObject|Object|SelectedVias|Selected)");
5204 static const char changehold_help
[] = N_("Changes the hole flag of objects.");
5206 /* %start-doc actions ChangeHole
5208 The "hole flag" of a via determines whether the via is a
5209 plated-through hole (not set), or an unplated hole (set).
5214 ActionChangeHole (int argc
, char **argv
, Coord x
, Coord y
)
5216 char *function
= ARG (0);
5219 switch (GetFunctionID (function
))
5221 case F_ToggleObject
:
5225 void *ptr1
, *ptr2
, *ptr3
;
5227 gui
->get_coords (_("Select an Object"), &x
, &y
);
5228 if ((type
= SearchScreen (x
, y
, VIA_TYPE
,
5229 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5230 && ChangeHole ((PinType
*) ptr3
))
5231 IncrementUndoSerialNumber ();
5235 case F_SelectedVias
:
5237 if (ChangeSelectedHole ())
5238 SetChangedFlag (true);
5245 /* --------------------------------------------------------------------------- */
5247 static const char changepaste_syntax
[] =
5248 N_("ChangePaste(ToggleObject|Object|SelectedPads|Selected)");
5250 static const char changepaste_help
[] =
5251 N_("Changes the no paste flag of objects.");
5253 /* %start-doc actions ChangePaste
5255 The "no paste flag" of a pad determines whether the solderpaste
5256 stencil will have an opening for the pad (no set) or if there wil be
5257 no solderpaste on the pad (set). This is used for things such as
5263 ActionChangePaste (int argc
, char **argv
, Coord x
, Coord y
)
5265 char *function
= ARG (0);
5268 switch (GetFunctionID (function
))
5270 case F_ToggleObject
:
5274 void *ptr1
, *ptr2
, *ptr3
;
5276 gui
->get_coords (_("Select an Object"), &x
, &y
);
5277 if ((type
= SearchScreen (x
, y
, PAD_TYPE
,
5278 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5279 && ChangePaste ((PadType
*) ptr3
))
5280 IncrementUndoSerialNumber ();
5284 case F_SelectedPads
:
5286 if (ChangeSelectedPaste ())
5287 SetChangedFlag (true);
5294 /* --------------------------------------------------------------------------- */
5296 static const char select_syntax
[] =
5297 N_("Select(Object|ToggleObject)\n"
5298 "Select(All|Block|Connection)\n"
5299 "Select(ElementByName|ObjectByName|PadByName|PinByName)\n"
5300 "Select(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5301 "Select(TextByName|ViaByName|NetByName)\n"
5302 "Select(TextByName|ViaByName|NetByName, Name)\n"
5305 static const char select_help
[] = N_("Toggles or sets the selection.");
5307 /* %start-doc actions Select
5319 These all rely on having a regular expression parser built into
5320 @code{pcb}. If the name is not specified then the user is prompted
5321 for a pattern, and all objects that match the pattern and are of the
5322 type specified are selected.
5326 Selects the object under the cursor.
5329 Selects all objects in a rectangle indicated by the cursor.
5332 Selects all objects on the board.
5335 Selects all connections with the ``found'' flag set.
5338 Selects all connections with the ``connected'' flag set.
5341 Converts the selected objects to an element. This uses the highest
5342 numbered paste buffer.
5349 ActionSelect (int argc
, char **argv
, Coord x
, Coord y
)
5351 char *function
= ARG (0);
5354 switch (GetFunctionID (function
))
5356 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5358 /* select objects by their names */
5359 case F_ElementByName
:
5360 type
= ELEMENT_TYPE
;
5362 case F_ObjectByName
:
5383 char *pattern
= ARG (1);
5387 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5389 if (SelectObjectByName (type
, pattern
, true))
5390 SetChangedFlag (true);
5391 if (ARG (1) == NULL
)
5396 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5398 /* select a single object */
5399 case F_ToggleObject
:
5401 if (SelectObject ())
5402 SetChangedFlag (true);
5405 /* all objects in block */
5410 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5411 Crosshair
.AttachedBox
.Point2
.X
);
5412 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5413 Crosshair
.AttachedBox
.Point2
.Y
);
5414 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5415 Crosshair
.AttachedBox
.Point2
.X
);
5416 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5417 Crosshair
.AttachedBox
.Point2
.Y
);
5418 notify_crosshair_change (false);
5420 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5421 SelectBlock (&box
, true))
5423 SetChangedFlag (true);
5424 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5426 notify_crosshair_change (true);
5430 /* select all visible objects */
5435 box
.X1
= -MAX_COORD
;
5436 box
.Y1
= -MAX_COORD
;
5439 if (SelectBlock (&box
, true))
5440 SetChangedFlag (true);
5444 /* all logical connections */
5446 if (SelectByFlag (FOUNDFLAG
, true))
5449 IncrementUndoSerialNumber ();
5450 SetChangedFlag (true);
5454 /* all physical connections */
5456 if (SelectByFlag (CONNECTEDFLAG
, true))
5459 IncrementUndoSerialNumber ();
5460 SetChangedFlag (true);
5467 Note
.Buffer
= Settings
.BufferNumber
;
5468 SetBufferNumber (MAX_BUFFER
- 1);
5469 ClearBuffer (PASTEBUFFER
);
5470 gui
->get_coords (_("Select the Element's Mark Location"), &x
, &y
);
5471 x
= GridFit (x
, PCB
->Grid
, PCB
->GridOffsetX
);
5472 y
= GridFit (y
, PCB
->Grid
, PCB
->GridOffsetY
);
5473 AddSelectedToBuffer (PASTEBUFFER
, x
, y
, true);
5474 SaveUndoSerialNumber ();
5476 ConvertBufferToElement (PASTEBUFFER
);
5477 RestoreUndoSerialNumber ();
5478 CopyPastebufferToLayout (x
, y
);
5479 SetBufferNumber (Note
.Buffer
);
5491 /* FLAG(have_regex,FlagHaveRegex,0) */
5493 FlagHaveRegex (int parm
)
5495 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5502 /* --------------------------------------------------------------------------- */
5504 static const char unselect_syntax
[] =
5505 N_("Unselect(All|Block|Connection)\n"
5506 "Unselect(ElementByName|ObjectByName|PadByName|PinByName)\n"
5507 "Unselect(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5508 "Unselect(TextByName|ViaByName)\n"
5509 "Unselect(TextByName|ViaByName, Name)\n");
5511 static const char unselect_help
[] =
5512 N_("Unselects the object at the pointer location or the specified objects.");
5514 /* %start-doc actions Unselect
5519 Unselect all objects.
5522 Unselect all objects in a rectangle given by the cursor.
5525 Unselect all connections with the ``found'' flag set.
5534 These all rely on having a regular expression parser built into
5535 @code{pcb}. If the name is not specified then the user is prompted
5536 for a pattern, and all objects that match the pattern and are of the
5537 type specified are unselected.
5545 ActionUnselect (int argc
, char **argv
, Coord x
, Coord y
)
5547 char *function
= ARG (0);
5550 switch (GetFunctionID (function
))
5552 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5554 /* select objects by their names */
5555 case F_ElementByName
:
5556 type
= ELEMENT_TYPE
;
5558 case F_ObjectByName
:
5579 char *pattern
= ARG (1);
5583 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5585 if (SelectObjectByName (type
, pattern
, false))
5586 SetChangedFlag (true);
5587 if (ARG (1) == NULL
)
5592 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5594 /* all objects in block */
5599 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5600 Crosshair
.AttachedBox
.Point2
.X
);
5601 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5602 Crosshair
.AttachedBox
.Point2
.Y
);
5603 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5604 Crosshair
.AttachedBox
.Point2
.X
);
5605 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5606 Crosshair
.AttachedBox
.Point2
.Y
);
5607 notify_crosshair_change (false);
5609 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5610 SelectBlock (&box
, false))
5612 SetChangedFlag (true);
5613 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5615 notify_crosshair_change (true);
5619 /* unselect all visible objects */
5624 box
.X1
= -MAX_COORD
;
5625 box
.Y1
= -MAX_COORD
;
5628 if (SelectBlock (&box
, false))
5629 SetChangedFlag (true);
5633 /* all logical connections */
5635 if (SelectByFlag (FOUNDFLAG
, false))
5638 IncrementUndoSerialNumber ();
5639 SetChangedFlag (true);
5643 /* all physical connections */
5645 if (SelectByFlag (CONNECTEDFLAG
, false))
5648 IncrementUndoSerialNumber ();
5649 SetChangedFlag (true);
5662 /* --------------------------------------------------------------------------- */
5664 static const char saveto_syntax
[] =
5665 N_("SaveTo(Layout|LayoutAs,filename)\n"
5666 "SaveTo(AllConnections|AllUnusedPins|ElementConnections,filename)\n"
5667 "SaveTo(PasteBuffer,filename)");
5669 static const char saveto_help
[] = N_("Saves data to a file.");
5671 /* %start-doc actions SaveTo
5676 Saves the current layout.
5679 Saves the current layout, and remembers the filename used.
5681 @item AllConnections
5682 Save all connections to a file.
5685 List all unused pins to a file.
5687 @item ElementConnections
5688 Save connections to the element at the cursor to a file.
5691 Save the content of the active Buffer to a file. This is the graphical way to create a footprint.
5698 ActionSaveTo (int argc
, char **argv
, Coord x
, Coord y
)
5706 if (strcasecmp (function
, "Layout") == 0)
5708 if (SavePCB (PCB
->Filename
) == 0)
5709 SetChangedFlag (false);
5716 if (strcasecmp (function
, "LayoutAs") == 0)
5718 if (SavePCB (name
) == 0)
5720 SetChangedFlag (false);
5721 free (PCB
->Filename
);
5722 PCB
->Filename
= strdup (name
);
5723 if (gui
->notify_filename_changed
!= NULL
)
5724 gui
->notify_filename_changed ();
5729 if (strcasecmp (function
, "AllConnections") == 0)
5733 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5735 LookupConnectionsToAllElements (fp
);
5737 SetChangedFlag (true);
5742 if (strcasecmp (function
, "AllUnusedPins") == 0)
5746 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5748 LookupUnusedPins (fp
);
5750 SetChangedFlag (true);
5755 if (strcasecmp (function
, "ElementConnections") == 0)
5757 ElementType
*element
;
5762 if ((SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
5763 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
5765 element
= (ElementType
*) ptrtmp
;
5767 CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5769 LookupElementConnections (element
, fp
);
5771 SetChangedFlag (true);
5777 if (strcasecmp (function
, "PasteBuffer") == 0)
5779 return SaveBufferElements (name
);
5785 /* --------------------------------------------------------------------------- */
5787 static const char savesettings_syntax
[] =
5788 N_("SaveSettings()\n"
5789 "SaveSettings(local)");
5791 static const char savesettings_help
[] = N_("Saves settings.");
5793 /* %start-doc actions SaveSettings
5795 If you pass no arguments, the settings are stored in
5796 @code{$HOME/.pcb/settings}. If you pass the word @code{local} they're
5797 saved in @code{./pcb.settings}.
5802 ActionSaveSettings (int argc
, char **argv
, Coord x
, Coord y
)
5804 int locally
= argc
> 0 ? (strncasecmp (argv
[0], "local", 5) == 0) : 0;
5805 hid_save_settings (locally
);
5809 /* --------------------------------------------------------------------------- */
5811 static const char loadfrom_syntax
[] =
5812 N_("LoadFrom(Layout|LayoutToBuffer|ElementToBuffer|Netlist|Revert,filename)");
5814 static const char loadfrom_help
[] = N_("Load layout data from a file.");
5816 /* %start-doc actions LoadFrom
5818 This action assumes you know what the filename is. The various GUIs
5819 should have a similar @code{Load} action where the filename is
5820 optional, and will provide their own file selection mechanism to let
5821 you choose the file name.
5826 Loads an entire PCB layout, replacing the current one.
5828 @item LayoutToBuffer
5829 Loads an entire PCB layout to the paste buffer.
5831 @item ElementToBuffer
5832 Loads the given element file into the paste buffer. Element files
5833 contain only a single @code{Element} definition, such as the
5834 ``newlib'' library uses.
5837 Loads a new netlist, replacing any current netlist.
5840 Re-loads the current layout from its disk file, reverting any changes
5848 ActionLoadFrom (int argc
, char **argv
, Coord x
, Coord y
)
5859 if (strcasecmp (function
, "ElementToBuffer") == 0)
5861 notify_crosshair_change (false);
5862 if (LoadElementToBuffer (PASTEBUFFER
, name
, true))
5863 SetMode (PASTEBUFFER_MODE
);
5864 notify_crosshair_change (true);
5867 else if (strcasecmp (function
, "LayoutToBuffer") == 0)
5869 notify_crosshair_change (false);
5870 if (LoadLayoutToBuffer (PASTEBUFFER
, name
))
5871 SetMode (PASTEBUFFER_MODE
);
5872 notify_crosshair_change (true);
5875 else if (strcasecmp (function
, "Layout") == 0)
5877 if (!PCB
->Changed
||
5878 gui
->confirm_dialog (_("OK to override layout data?"), 0))
5882 else if (strcasecmp (function
, "Netlist") == 0)
5884 if (PCB
->Netlistname
)
5885 free (PCB
->Netlistname
);
5886 PCB
->Netlistname
= StripWhiteSpaceAndDup (name
);
5887 FreeLibraryMemory (&PCB
->NetlistLib
);
5888 ImportNetlist (PCB
->Netlistname
);
5891 else if (strcasecmp (function
, "Revert") == 0 && PCB
->Filename
5893 || gui
->confirm_dialog (_("OK to override changes?"), 0)))
5901 /* --------------------------------------------------------------------------- */
5903 static const char new_syntax
[] = N_("New([name])");
5905 static const char new_help
[] = N_("Starts a new layout.");
5907 /* %start-doc actions New
5909 If a name is not given, one is prompted for.
5914 ActionNew (int argc
, char **argv
, Coord x
, Coord y
)
5916 char *name
= ARG (0);
5918 if (!PCB
->Changed
|| gui
->confirm_dialog (_("OK to clear layout data?"), 0))
5921 name
= strdup (name
);
5923 name
= gui
->prompt_for (_("Enter the layout name:"), "");
5928 notify_crosshair_change (false);
5929 /* do emergency saving
5930 * clear the old struct and allocate memory for the new one
5932 if (PCB
->Changed
&& Settings
.SaveInTMP
)
5936 PCB
= CreateNewPCB (true);
5937 CreateNewPCBPost (PCB
, 1);
5939 /* setup the new name and reset some values to default */
5943 ResetStackAndVisibility ();
5944 SetCrosshairRange (0, 0, PCB
->MaxWidth
, PCB
->MaxHeight
);
5945 CenterDisplay (PCB
->MaxWidth
/ 2, PCB
->MaxHeight
/ 2);
5948 hid_action ("PCBChanged");
5949 notify_crosshair_change (true);
5955 /* ---------------------------------------------------------------------------
5956 * no operation, just for testing purposes
5957 * syntax: Bell(volume)
5960 ActionBell (char *volume
)
5965 /* --------------------------------------------------------------------------- */
5967 static const char pastebuffer_syntax
[] =
5968 N_("PasteBuffer(AddSelected|Clear|1..MAX_BUFFER)\n"
5969 "PasteBuffer(Rotate, 1..3)\n"
5970 "PasteBuffer(Convert|Save|Restore|Mirror)\n"
5971 "PasteBuffer(ToLayout, X, Y, units)");
5973 static const char pastebuffer_help
[] =
5974 N_("Various operations on the paste buffer.");
5976 /* %start-doc actions PasteBuffer
5978 There are a number of paste buffers; the actual limit is a
5979 compile-time constant @code{MAX_BUFFER} in @file{globalconst.h}. It
5980 is currently @code{5}. One of these is the ``current'' paste buffer,
5981 often referred to as ``the'' paste buffer.
5986 Copies the selected objects to the current paste buffer.
5989 Remove all objects from the current paste buffer.
5992 Convert the current paste buffer to an element. Vias are converted to
5993 pins, lines are converted to pads.
5996 Convert any elements in the paste buffer back to vias and lines.
5999 Flip all objects in the paste buffer vertically (up/down flip). To mirror
6000 horizontally, combine this with rotations.
6003 Rotates the current buffer. The number to pass is 1..3, where 1 means
6004 90 degrees counter clockwise, 2 means 180 degrees, and 3 means 90
6005 degrees clockwise (270 CCW).
6008 Saves any elements in the current buffer to the indicated file.
6011 Pastes any elements in the current buffer to the indicated X, Y
6012 coordinates in the layout. The @code{X} and @code{Y} are treated like
6013 @code{delta} is for many other objects. For each, if it's prefixed by
6014 @code{+} or @code{-}, then that amount is relative to the last
6015 location. Otherwise, it's absolute. Units can be
6016 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
6017 units, currently 1/100 mil.
6021 Selects the given buffer to be the current paste buffer.
6028 ActionPasteBuffer (int argc
, char **argv
, Coord x
, Coord y
)
6030 char *function
= argc
? argv
[0] : (char *)"";
6031 char *sbufnum
= argc
> 1 ? argv
[1] : (char *)"";
6033 static char *default_file
= NULL
;
6036 notify_crosshair_change (false);
6039 switch (GetFunctionID (function
))
6041 /* clear contents of paste buffer */
6043 ClearBuffer (PASTEBUFFER
);
6046 /* copies objects to paste buffer */
6048 AddSelectedToBuffer (PASTEBUFFER
, 0, 0, false);
6051 /* converts buffer contents into an element */
6053 ConvertBufferToElement (PASTEBUFFER
);
6056 /* break up element for editing */
6058 SmashBufferElement (PASTEBUFFER
);
6063 MirrorBuffer (PASTEBUFFER
);
6069 RotateBuffer (PASTEBUFFER
, (BYTE
) atoi (sbufnum
));
6070 SetCrosshairRangeToBuffer ();
6075 if (PASTEBUFFER
->Data
->ElementN
== 0)
6077 Message (_("Buffer has no elements!\n"));
6083 name
= gui
->fileselect (_("Save Paste Buffer As ..."),
6084 _("Choose a file to save the contents of the\n"
6085 "paste buffer to.\n"),
6086 default_file
, ".fp", "footprint",
6091 free (default_file
);
6092 default_file
= NULL
;
6096 default_file
= strdup (name
);
6107 if ((exist
= fopen (name
, "r")))
6111 confirm_dialog (_("File exists! Ok to overwrite?"), 0))
6112 SaveBufferElements (name
);
6115 SaveBufferElements (name
);
6117 if (free_name
&& name
)
6124 static Coord oldx
= 0, oldy
= 0;
6132 else if (argc
== 3 || argc
== 4)
6134 x
= GetValue (ARG (1), ARG (3), &absolute
);
6137 y
= GetValue (ARG (2), ARG (3), &absolute
);
6143 notify_crosshair_change (true);
6144 AFAIL (pastebuffer
);
6149 if (CopyPastebufferToLayout (x
, y
))
6150 SetChangedFlag (true);
6157 int number
= atoi (function
);
6159 /* correct number */
6161 SetBufferNumber (number
- 1);
6166 notify_crosshair_change (true);
6170 /* --------------------------------------------------------------------------- */
6172 static const char undo_syntax
[] = N_("Undo()\n"
6175 static const char undo_help
[] = N_("Undo recent changes.");
6177 /* %start-doc actions Undo
6179 The unlimited undo feature of @code{Pcb} allows you to recover from
6180 most operations that materially affect you work. Calling
6181 @code{Undo()} without any parameter recovers from the last (non-undo)
6182 operation. @code{ClearList} is used to release the allocated
6183 memory. @code{ClearList} is called whenever a new layout is started or
6184 loaded. See also @code{Redo} and @code{Atomic}.
6186 Note that undo groups operations by serial number; changes with the
6187 same serial number will be undone (or redone) as a group. See
6193 ActionUndo (int argc
, char **argv
, Coord x
, Coord y
)
6195 char *function
= ARG (0);
6196 if (!function
|| !*function
)
6198 /* don't allow undo in the middle of an operation */
6199 if (Settings
.Mode
!= POLYGONHOLE_MODE
&&
6200 Crosshair
.AttachedObject
.State
!= STATE_FIRST
)
6202 if (Crosshair
.AttachedBox
.State
!= STATE_FIRST
6203 && Settings
.Mode
!= ARC_MODE
)
6205 /* undo the last operation */
6207 notify_crosshair_change (false);
6208 if ((Settings
.Mode
== POLYGON_MODE
||
6209 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6210 Crosshair
.AttachedPolygon
.PointN
)
6212 GoToPreviousPoint ();
6213 notify_crosshair_change (true);
6216 /* move anchor point if undoing during line creation */
6217 if (Settings
.Mode
== LINE_MODE
)
6219 if (Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6221 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6222 Undo (true); /* undo the connection find */
6223 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
6224 SetLocalRef (0, 0, false);
6225 notify_crosshair_change (true);
6228 if (Crosshair
.AttachedLine
.State
== STATE_THIRD
)
6231 void *ptr1
, *ptr3
, *ptrtmp
;
6233 /* this search is guaranteed to succeed */
6234 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6236 Crosshair
.AttachedLine
.Point1
.X
,
6237 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6238 ptr2
= (LineType
*) ptrtmp
;
6240 /* save both ends of line */
6241 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point1
.X
;
6242 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point1
.Y
;
6243 if ((type
= Undo (true)))
6244 SetChangedFlag (true);
6245 /* check that the undo was of the right type */
6246 if ((type
& UNDO_CREATE
) == 0)
6248 /* wrong undo type, restore anchor points */
6249 Crosshair
.AttachedLine
.Point2
.X
=
6250 Crosshair
.AttachedLine
.Point1
.X
;
6251 Crosshair
.AttachedLine
.Point2
.Y
=
6252 Crosshair
.AttachedLine
.Point1
.Y
;
6253 notify_crosshair_change (true);
6256 /* move to new anchor */
6257 Crosshair
.AttachedLine
.Point1
.X
=
6258 Crosshair
.AttachedLine
.Point2
.X
;
6259 Crosshair
.AttachedLine
.Point1
.Y
=
6260 Crosshair
.AttachedLine
.Point2
.Y
;
6261 /* check if an intermediate point was removed */
6262 if (type
& UNDO_REMOVE
)
6264 /* this search should find the restored line */
6265 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6268 Crosshair
.AttachedLine
.Point2
.X
,
6269 Crosshair
.AttachedLine
.Point2
.Y
, 0);
6270 ptr2
= (LineType
*) ptrtmp
;
6271 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6273 /* undo loses CONNECTEDFLAG and FOUNDFLAG */
6274 SET_FLAG(CONNECTEDFLAG
, ptr2
);
6275 SET_FLAG(FOUNDFLAG
, ptr2
);
6276 DrawLine (CURRENT
, ptr2
);
6278 Crosshair
.AttachedLine
.Point1
.X
=
6279 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point2
.X
;
6280 Crosshair
.AttachedLine
.Point1
.Y
=
6281 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point2
.Y
;
6283 FitCrosshairIntoGrid (Crosshair
.X
, Crosshair
.Y
);
6284 AdjustAttachedObjects ();
6285 if (--addedLines
== 0)
6287 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
6288 lastLayer
= CURRENT
;
6292 /* this search is guaranteed to succeed too */
6293 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6296 Crosshair
.AttachedLine
.Point1
.X
,
6297 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6298 ptr2
= (LineType
*) ptrtmp
;
6299 lastLayer
= (LayerType
*) ptr1
;
6301 notify_crosshair_change (true);
6305 if (Settings
.Mode
== ARC_MODE
)
6307 if (Crosshair
.AttachedBox
.State
== STATE_SECOND
)
6309 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
6310 notify_crosshair_change (true);
6313 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
)
6315 void *ptr1
, *ptr2
, *ptr3
;
6317 /* guaranteed to succeed */
6318 SearchObjectByLocation (ARC_TYPE
, &ptr1
, &ptr2
, &ptr3
,
6319 Crosshair
.AttachedBox
.Point1
.X
,
6320 Crosshair
.AttachedBox
.Point1
.Y
, 0);
6321 bx
= GetArcEnds ((ArcType
*) ptr2
);
6322 Crosshair
.AttachedBox
.Point1
.X
=
6323 Crosshair
.AttachedBox
.Point2
.X
= bx
->X1
;
6324 Crosshair
.AttachedBox
.Point1
.Y
=
6325 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y1
;
6326 AdjustAttachedObjects ();
6327 if (--addedLines
== 0)
6328 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
6331 /* undo the last destructive operation */
6333 SetChangedFlag (true);
6337 switch (GetFunctionID (function
))
6339 /* clear 'undo objects' list */
6341 ClearUndoList (false);
6345 notify_crosshair_change (true);
6349 /* --------------------------------------------------------------------------- */
6351 static const char redo_syntax
[] = N_("Redo()");
6353 static const char redo_help
[] = N_("Redo recent \"undo\" operations.");
6355 /* %start-doc actions Redo
6357 This routine allows you to recover from the last undo command. You
6358 might want to do this if you thought that undo was going to revert
6359 something other than what it actually did (in case you are confused
6360 about which operations are un-doable), or if you have been backing up
6361 through a long undo list and over-shoot your stopping point. Any
6362 change that is made since the undo in question will trim the redo
6363 list. For example if you add ten lines, then undo three of them you
6364 could use redo to put them back, but if you move a line on the board
6365 before performing the redo, you will lose the ability to "redo" the
6366 three "undone" lines.
6371 ActionRedo (int argc
, char **argv
, Coord x
, Coord y
)
6373 if (((Settings
.Mode
== POLYGON_MODE
||
6374 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6375 Crosshair
.AttachedPolygon
.PointN
) ||
6376 Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6378 notify_crosshair_change (false);
6381 SetChangedFlag (true);
6382 if (Settings
.Mode
== LINE_MODE
&&
6383 Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
6385 LineType
*line
= g_list_last (CURRENT
->Line
)->data
;
6386 Crosshair
.AttachedLine
.Point1
.X
=
6387 Crosshair
.AttachedLine
.Point2
.X
= line
->Point2
.X
;
6388 Crosshair
.AttachedLine
.Point1
.Y
=
6389 Crosshair
.AttachedLine
.Point2
.Y
= line
->Point2
.Y
;
6393 notify_crosshair_change (true);
6397 /* --------------------------------------------------------------------------- */
6399 static const char polygon_syntax
[] = N_("Polygon(Close|PreviousPoint)");
6401 static const char polygon_help
[] = N_("Some polygon related stuff.");
6403 /* %start-doc actions Polygon
6405 Polygons need a special action routine to make life easier.
6410 Creates the final segment of the polygon. This may fail if clipping
6411 to 45 degree lines is switched on, in which case a warning is issued.
6414 Resets the newly entered corner to the previous one. The Undo action
6415 will call Polygon(PreviousPoint) when appropriate to do so.
6422 ActionPolygon (int argc
, char **argv
, Coord x
, Coord y
)
6424 char *function
= ARG (0);
6425 if (function
&& Settings
.Mode
== POLYGON_MODE
)
6427 notify_crosshair_change (false);
6428 switch (GetFunctionID (function
))
6430 /* close open polygon if possible */
6435 /* go back to the previous point */
6436 case F_PreviousPoint
:
6437 GoToPreviousPoint ();
6440 notify_crosshair_change (true);
6445 /* --------------------------------------------------------------------------- */
6447 static const char routestyle_syntax
[] = N_("RouteStyle(1|2|3|4)");
6449 static const char routestyle_help
[] =
6450 N_("Copies the indicated routing style into the current sizes.");
6452 /* %start-doc actions RouteStyle
6457 ActionRouteStyle (int argc
, char **argv
, Coord x
, Coord y
)
6459 char *str
= ARG (0);
6460 RouteStyleType
*rts
;
6465 number
= atoi (str
);
6466 if (number
> 0 && number
<= NUM_STYLES
)
6468 rts
= &PCB
->RouteStyle
[number
- 1];
6469 SetLineSize (rts
->Thick
);
6470 SetViaSize (rts
->Diameter
, true);
6471 SetViaDrillingHole (rts
->Hole
, true);
6472 SetKeepawayWidth (rts
->Keepaway
);
6473 hid_action("RouteStylesChanged");
6480 /* --------------------------------------------------------------------------- */
6482 static const char moveobject_syntax
[] = N_("MoveObject(X,Y,dim)");
6484 static const char moveobject_help
[] =
6485 N_("Moves the object under the crosshair.");
6487 /* %start-doc actions MoveObject
6489 The @code{X} and @code{Y} are treated like @code{delta} is for many
6490 other objects. For each, if it's prefixed by @code{+} or @code{-},
6491 then that amount is relative. Otherwise, it's absolute. Units can be
6492 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
6493 units, currently 1/100 mil.
6498 ActionMoveObject (int argc
, char **argv
, Coord x
, Coord y
)
6500 char *x_str
= ARG (0);
6501 char *y_str
= ARG (1);
6502 char *units
= ARG (2);
6504 bool absolute1
, absolute2
;
6505 void *ptr1
, *ptr2
, *ptr3
;
6508 ny
= GetValue (y_str
, units
, &absolute1
);
6509 nx
= GetValue (x_str
, units
, &absolute2
);
6511 type
= SearchScreen (x
, y
, MOVE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6512 if (type
== NO_TYPE
)
6514 Message (_("Nothing found under crosshair\n"));
6521 Crosshair
.AttachedObject
.RubberbandN
= 0;
6522 if (TEST_FLAG (RUBBERBANDFLAG
, PCB
))
6523 LookupRubberbandLines (type
, ptr1
, ptr2
, ptr3
);
6524 if (type
== ELEMENT_TYPE
)
6525 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
6526 MoveObjectAndRubberband (type
, ptr1
, ptr2
, ptr3
, nx
, ny
);
6527 SetChangedFlag (true);
6531 /* --------------------------------------------------------------------------- */
6533 static const char movetocurrentlayer_syntax
[] =
6534 N_("MoveToCurrentLayer(Object|SelectedObjects)");
6536 static const char movetocurrentlayer_help
[] =
6537 N_("Moves objects to the current layer.");
6539 /* %start-doc actions MoveToCurrentLayer
6541 Note that moving an element from a component layer to a solder layer,
6542 or from solder to component, won't automatically flip it. Use the
6543 @code{Flip()} action to do that.
6548 ActionMoveToCurrentLayer (int argc
, char **argv
, Coord x
, Coord y
)
6550 char *function
= ARG (0);
6553 switch (GetFunctionID (function
))
6558 void *ptr1
, *ptr2
, *ptr3
;
6560 gui
->get_coords (_("Select an Object"), &x
, &y
);
6562 SearchScreen (x
, y
, MOVETOLAYER_TYPES
,
6563 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6564 if (MoveObjectToLayer (type
, ptr1
, ptr2
, ptr3
, CURRENT
, false))
6565 SetChangedFlag (true);
6569 case F_SelectedObjects
:
6571 if (MoveSelectedObjectsToLayer (CURRENT
))
6572 SetChangedFlag (true);
6580 static const char setsame_syntax
[] = N_("SetSame()");
6582 static const char setsame_help
[] =
6583 N_("Sets current layer and sizes to match indicated item.");
6585 /* %start-doc actions SetSame
6587 When invoked over any line, arc, polygon, or via, this changes the
6588 current layer to be the layer that item is on, and changes the current
6589 sizes (thickness, keepaway, drill, etc) according to that item.
6594 ActionSetSame (int argc
, char **argv
, Coord x
, Coord y
)
6596 void *ptr1
, *ptr2
, *ptr3
;
6598 LayerType
*layer
= CURRENT
;
6600 type
= SearchScreen (x
, y
, CLONE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6601 /* set layer current and size from line or arc */
6605 notify_crosshair_change (false);
6606 Settings
.LineThickness
= ((LineType
*) ptr2
)->Thickness
;
6607 Settings
.Keepaway
= ((LineType
*) ptr2
)->Clearance
/ 2;
6608 layer
= (LayerType
*) ptr1
;
6609 if (Settings
.Mode
!= LINE_MODE
)
6610 SetMode (LINE_MODE
);
6611 notify_crosshair_change (true);
6612 hid_action ("RouteStylesChanged");
6616 notify_crosshair_change (false);
6617 Settings
.LineThickness
= ((ArcType
*) ptr2
)->Thickness
;
6618 Settings
.Keepaway
= ((ArcType
*) ptr2
)->Clearance
/ 2;
6619 layer
= (LayerType
*) ptr1
;
6620 if (Settings
.Mode
!= ARC_MODE
)
6622 notify_crosshair_change (true);
6623 hid_action ("RouteStylesChanged");
6627 layer
= (LayerType
*) ptr1
;
6631 notify_crosshair_change (false);
6632 Settings
.ViaThickness
= ((PinType
*) ptr2
)->Thickness
;
6633 Settings
.ViaDrillingHole
= ((PinType
*) ptr2
)->DrillingHole
;
6634 Settings
.Keepaway
= ((PinType
*) ptr2
)->Clearance
/ 2;
6635 if (Settings
.Mode
!= VIA_MODE
)
6637 notify_crosshair_change (true);
6638 hid_action ("RouteStylesChanged");
6644 if (layer
!= CURRENT
)
6646 ChangeGroupVisibility (GetLayerNumber (PCB
->Data
, layer
), true, true);
6653 /* --------------------------------------------------------------------------- */
6655 static const char setflag_syntax
[] =
6656 N_("SetFlag(Object|Selected|SelectedObjects, flag)\n"
6657 "SetFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6658 "SetFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6659 "SetFlag(SelectedElements, flag)\n"
6660 "flag = square | octagon | thermal | join");
6662 static const char setflag_help
[] = N_("Sets flags on objects.");
6664 /* %start-doc actions SetFlag
6666 Turns the given flag on, regardless of its previous setting. See
6670 SetFlag(SelectedPins,thermal)
6676 ActionSetFlag (int argc
, char **argv
, Coord x
, Coord y
)
6678 char *function
= ARG (0);
6679 char *flag
= ARG (1);
6680 ChangeFlag (function
, flag
, 1, "SetFlag");
6684 /* --------------------------------------------------------------------------- */
6686 static const char clrflag_syntax
[] =
6687 N_("ClrFlag(Object|Selected|SelectedObjects, flag)\n"
6688 "ClrFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6689 "ClrFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6690 "ClrFlag(SelectedElements, flag)\n"
6691 "flag = square | octagon | thermal | join");
6693 static const char clrflag_help
[] = N_("Clears flags on objects.");
6695 /* %start-doc actions ClrFlag
6697 Turns the given flag off, regardless of its previous setting. See
6701 ClrFlag(SelectedLines,join)
6707 ActionClrFlag (int argc
, char **argv
, Coord x
, Coord y
)
6709 char *function
= ARG (0);
6710 char *flag
= ARG (1);
6711 ChangeFlag (function
, flag
, 0, "ClrFlag");
6715 /* --------------------------------------------------------------------------- */
6717 static const char changeflag_syntax
[] =
6718 N_("ChangeFlag(Object|Selected|SelectedObjects, flag, value)\n"
6719 "ChangeFlag(SelectedLines|SelectedPins|SelectedVias, flag, value)\n"
6720 "ChangeFlag(SelectedPads|SelectedTexts|SelectedNames, flag, value)\n"
6721 "ChangeFlag(SelectedElements, flag, value)\n"
6722 "flag = square | octagon | thermal | join\n"
6725 static const char changeflag_help
[] = N_("Sets or clears flags on objects.");
6727 /* %start-doc actions ChangeFlag
6729 Toggles the given flag on the indicated object(s). The flag may be
6730 one of the flags listed above (square, octagon, thermal, join). The
6731 value may be the number 0 or 1. If the value is 0, the flag is
6732 cleared. If the value is 1, the flag is set.
6737 ActionChangeFlag (int argc
, char **argv
, Coord x
, Coord y
)
6739 char *function
= ARG (0);
6740 char *flag
= ARG (1);
6741 int value
= argc
> 2 ? atoi (argv
[2]) : -1;
6742 if (value
!= 0 && value
!= 1)
6745 ChangeFlag (function
, flag
, value
, "ChangeFlag");
6751 ChangeFlag (char *what
, char *flag_name
, int value
, char *cmd_name
)
6753 bool (*set_object
) (int, void *, void *, void *);
6754 bool (*set_selected
) (int);
6756 if (NSTRCMP (flag_name
, "square") == 0)
6758 set_object
= value
? SetObjectSquare
: ClrObjectSquare
;
6759 set_selected
= value
? SetSelectedSquare
: ClrSelectedSquare
;
6761 else if (NSTRCMP (flag_name
, "octagon") == 0)
6763 set_object
= value
? SetObjectOctagon
: ClrObjectOctagon
;
6764 set_selected
= value
? SetSelectedOctagon
: ClrSelectedOctagon
;
6766 else if (NSTRCMP (flag_name
, "join") == 0)
6768 /* Note: these are backwards, because the flag is "clear" but
6769 the command is "join". */
6770 set_object
= value
? ClrObjectJoin
: SetObjectJoin
;
6771 set_selected
= value
? ClrSelectedJoin
: SetSelectedJoin
;
6775 Message (_("%s(): Flag \"%s\" is not valid\n"), cmd_name
, flag_name
);
6779 switch (GetFunctionID (what
))
6784 void *ptr1
, *ptr2
, *ptr3
;
6787 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
6788 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6789 if (TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
6790 Message (_("Sorry, the object is locked\n"));
6791 if (set_object (type
, ptr1
, ptr2
, ptr3
))
6792 SetChangedFlag (true);
6796 case F_SelectedVias
:
6797 if (set_selected (VIA_TYPE
))
6798 SetChangedFlag (true);
6801 case F_SelectedPins
:
6802 if (set_selected (PIN_TYPE
))
6803 SetChangedFlag (true);
6806 case F_SelectedPads
:
6807 if (set_selected (PAD_TYPE
))
6808 SetChangedFlag (true);
6811 case F_SelectedLines
:
6812 if (set_selected (LINE_TYPE
))
6813 SetChangedFlag (true);
6816 case F_SelectedTexts
:
6817 if (set_selected (TEXT_TYPE
))
6818 SetChangedFlag (true);
6821 case F_SelectedNames
:
6822 if (set_selected (ELEMENTNAME_TYPE
))
6823 SetChangedFlag (true);
6826 case F_SelectedElements
:
6827 if (set_selected (ELEMENT_TYPE
))
6828 SetChangedFlag (true);
6832 case F_SelectedObjects
:
6833 if (set_selected (CHANGESIZE_TYPES
))
6834 SetChangedFlag (true);
6839 /* --------------------------------------------------------------------------- */
6841 static const char executefile_syntax
[] = N_("ExecuteFile(filename)");
6843 static const char executefile_help
[] = N_("Run actions from the given file.");
6845 /* %start-doc actions ExecuteFile
6847 Lines starting with @code{#} are ignored.
6852 ActionExecuteFile (int argc
, char **argv
, Coord x
, Coord y
)
6861 AFAIL (executefile
);
6865 if ((fp
= fopen (fname
, "r")) == NULL
)
6867 fprintf (stderr
, _("Could not open actions file \"%s\".\n"), fname
);
6872 defer_needs_update
= 0;
6873 while (fgets (line
, sizeof (line
), fp
) != NULL
)
6878 /* eat the trailing newline */
6879 while (*sp
&& *sp
!= '\r' && *sp
!= '\n')
6883 /* eat leading spaces and tabs */
6885 while (*sp
&& (*sp
== ' ' || *sp
== '\t'))
6889 * if we have anything left and its not a comment line
6893 if (*sp
&& *sp
!= '#')
6895 /*Message ("%s : line %-3d : \"%s\"\n", fname, n, sp);*/
6896 hid_parse_actions (sp
);
6901 if (defer_needs_update
)
6903 IncrementUndoSerialNumber ();
6904 gui
->invalidate_all ();
6910 /* --------------------------------------------------------------------------- */
6913 ActionPSCalib (int argc
, char **argv
, Coord x
, Coord y
)
6915 HID
*ps
= hid_find_exporter ("ps");
6916 ps
->calibrate (0.0,0.0);
6920 /* --------------------------------------------------------------------------- */
6922 static ElementType
*element_cache
= NULL
;
6924 static ElementType
*
6925 find_element_by_refdes (char *refdes
)
6928 && NAMEONPCB_NAME(element_cache
)
6929 && strcmp (NAMEONPCB_NAME(element_cache
), refdes
) == 0)
6930 return element_cache
;
6932 ELEMENT_LOOP (PCB
->Data
);
6934 if (NAMEONPCB_NAME(element
)
6935 && strcmp (NAMEONPCB_NAME(element
), refdes
) == 0)
6937 element_cache
= element
;
6938 return element_cache
;
6945 static AttributeType
*
6946 lookup_attr (AttributeListType
*list
, const char *name
)
6949 for (i
=0; i
<list
->Number
; i
++)
6950 if (strcmp (list
->List
[i
].name
, name
) == 0)
6951 return & list
->List
[i
];
6956 delete_attr (AttributeListType
*list
, AttributeType
*attr
)
6958 int idx
= attr
- list
->List
;
6959 if (idx
< 0 || idx
>= list
->Number
)
6961 if (list
->Number
- idx
> 1)
6962 memmove (attr
, attr
+1, (list
->Number
- idx
- 1) * sizeof(AttributeType
));
6966 /* ---------------------------------------------------------------- */
6967 static const char elementlist_syntax
[] =
6968 N_("ElementList(Start|Done|Need,<refdes>,<footprint>,<value>)");
6970 static const char elementlist_help
[] =
6971 N_("Adds the given element if it doesn't already exist.");
6973 /* %start-doc actions elementlist
6978 Indicates the start of an element list; call this before any Need
6982 Searches the board for an element with a matching refdes.
6984 If found, the value and footprint are updated.
6986 If not found, a new element is created with the given footprint and value.
6989 Compares the list of elements needed since the most recent
6990 @code{start} with the list of elements actually on the board. Any
6991 elements that weren't listed are selected, so that the user may delete
6998 static int number_of_footprints_not_found
;
7001 parse_layout_attribute_units (char *name
, int def
)
7003 const char *as
= AttributeGet (PCB
, name
);
7006 return GetValue (as
, NULL
, NULL
);
7010 ActionElementList (int argc
, char **argv
, Coord x
, Coord y
)
7012 ElementType
*e
= NULL
;
7013 char *refdes
, *value
, *footprint
, *old
;
7015 char *function
= argv
[0];
7018 printf("Entered ActionElementList, executing function %s\n", function
);
7021 if (strcasecmp (function
, "start") == 0)
7023 ELEMENT_LOOP (PCB
->Data
);
7025 CLEAR_FLAG (FOUNDFLAG
, element
);
7028 element_cache
= NULL
;
7029 number_of_footprints_not_found
= 0;
7033 if (strcasecmp (function
, "done") == 0)
7035 ELEMENT_LOOP (PCB
->Data
);
7037 if (TEST_FLAG (FOUNDFLAG
, element
))
7039 CLEAR_FLAG (FOUNDFLAG
, element
);
7041 else if (! EMPTY_STRING_P (NAMEONPCB_NAME (element
)))
7043 /* Unnamed elements should remain untouched */
7044 SET_FLAG (SELECTEDFLAG
, element
);
7048 if (number_of_footprints_not_found
> 0)
7049 gui
->confirm_dialog (_("Not all requested footprints were found.\n"
7050 "See the message log for details"),
7055 if (strcasecmp (function
, "need") != 0)
7056 AFAIL (elementlist
);
7059 AFAIL (elementlist
);
7068 args
[0] = footprint
;
7073 printf(" ... footprint = %s\n", footprint
);
7074 printf(" ... refdes = %s\n", refdes
);
7075 printf(" ... value = %s\n", value
);
7078 e
= find_element_by_refdes (refdes
);
7085 printf(" ... Footprint not on board, need to add it.\n");
7087 /* Not on board, need to add it. */
7088 if (LoadFootprint(argc
, args
, x
, y
))
7090 number_of_footprints_not_found
++;
7094 nx
= PCB
->MaxWidth
/ 2;
7095 ny
= PCB
->MaxHeight
/ 2;
7096 d
= MIN (PCB
->MaxWidth
, PCB
->MaxHeight
) / 10;
7098 nx
= parse_layout_attribute_units ("import::newX", nx
);
7099 ny
= parse_layout_attribute_units ("import::newY", ny
);
7100 d
= parse_layout_attribute_units ("import::disperse", d
);
7104 nx
+= rand () % (d
*2) - d
;
7105 ny
+= rand () % (d
*2) - d
;
7110 if (nx
>= PCB
->MaxWidth
)
7111 nx
= PCB
->MaxWidth
- 1;
7114 if (ny
>= PCB
->MaxHeight
)
7115 ny
= PCB
->MaxHeight
- 1;
7117 /* Place components onto center of board. */
7118 if (CopyPastebufferToLayout (nx
, ny
))
7119 SetChangedFlag (true);
7122 else if (e
&& DESCRIPTION_NAME(e
) && strcmp (DESCRIPTION_NAME(e
), footprint
) != 0)
7125 printf(" ... Footprint on board, but different from footprint loaded.\n");
7131 /* Different footprint, we need to swap them out. */
7132 if (LoadFootprint(argc
, args
, x
, y
))
7134 number_of_footprints_not_found
++;
7138 er
= ElementOrientation (e
);
7139 pe
= PASTEBUFFER
->Data
->Element
->data
;
7141 MirrorElementCoordinates (PASTEBUFFER
->Data
, pe
, pe
->MarkY
*2 - PCB
->MaxHeight
);
7142 pr
= ElementOrientation (pe
);
7148 RotateElementLowLevel (PASTEBUFFER
->Data
, pe
, pe
->MarkX
, pe
->MarkY
, (er
-pr
+4)%4);
7150 for (i
=0; i
<MAX_ELEMENTNAMES
; i
++)
7152 pe
->Name
[i
].X
= e
->Name
[i
].X
- mx
+ pe
->MarkX
;
7153 pe
->Name
[i
].Y
= e
->Name
[i
].Y
- my
+ pe
->MarkY
;
7154 pe
->Name
[i
].Direction
= e
->Name
[i
].Direction
;
7155 pe
->Name
[i
].Scale
= e
->Name
[i
].Scale
;
7160 if (CopyPastebufferToLayout (mx
, my
))
7161 SetChangedFlag (true);
7164 /* Now reload footprint */
7165 element_cache
= NULL
;
7166 e
= find_element_by_refdes (refdes
);
7168 old
= ChangeElementText (PCB
, PCB
->Data
, e
, NAMEONPCB_INDEX
, strdup (refdes
));
7171 old
= ChangeElementText (PCB
, PCB
->Data
, e
, VALUE_INDEX
, strdup (value
));
7175 SET_FLAG (FOUNDFLAG
, e
);
7178 printf(" ... Leaving ActionElementList.\n");
7184 /* ---------------------------------------------------------------- */
7185 static const char elementsetattr_syntax
[] =
7186 N_("ElementSetAttr(refdes,name[,value])");
7188 static const char elementsetattr_help
[] =
7189 N_("Sets or clears an element-specific attribute.");
7191 /* %start-doc actions elementsetattr
7193 If a value is specified, the named attribute is added (if not already
7194 present) or changed (if it is) to the given value. If the value is
7195 not specified, the given attribute is removed if present.
7200 ActionElementSetAttr (int argc
, char **argv
, Coord x
, Coord y
)
7202 ElementType
*e
= NULL
;
7203 char *refdes
, *name
, *value
;
7204 AttributeType
*attr
;
7208 AFAIL (changepinname
);
7215 ELEMENT_LOOP (PCB
->Data
);
7217 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
7227 Message(_("Cannot change attribute of %s - element not found\n"), refdes
);
7231 attr
= lookup_attr (&e
->Attributes
, name
);
7236 attr
->value
= strdup (value
);
7238 if (attr
&& ! value
)
7240 delete_attr (& e
->Attributes
, attr
);
7244 CreateNewAttribute (& e
->Attributes
, name
, value
);
7250 /* ---------------------------------------------------------------- */
7251 static const char execcommand_syntax
[] = N_("ExecCommand(command)");
7253 static const char execcommand_help
[] = N_("Runs a command.");
7255 /* %start-doc actions execcommand
7257 Runs the given command, which is a system executable.
7262 ActionExecCommand (int argc
, char **argv
, Coord x
, Coord y
)
7268 AFAIL (execcommand
);
7273 if (system (command
))
7278 /* ---------------------------------------------------------------- */
7281 pcb_spawnvp (char **argv
)
7283 #ifdef HAVE__SPAWNVP
7284 int result
= _spawnvp (_P_WAIT
, argv
[0], (const char * const *) argv
);
7295 Message(_("Cannot fork!"));
7301 execvp (argv
[0], argv
);
7314 /* ---------------------------------------------------------------- */
7316 * Creates a new temporary file name. Hopefully the operating system
7317 * provides a mkdtemp() function to securily create a temporary
7318 * directory with mode 0700. If so then that directory is created and
7319 * the returned string is made up of the directory plus the name
7320 * variable. For example:
7322 * tempfile_name_new ("myfile") might return
7323 * "/var/tmp/pcb.123456/myfile".
7325 * If mkdtemp() is not available then 'name' is ignored and the
7326 * insecure tmpnam() function is used.
7328 * Files/names created with tempfile_name_new() should be unlinked
7329 * with tempfile_unlink to make sure the temporary directory is also
7330 * removed when mkdtemp() is used.
7333 tempfile_name_new (char * name
)
7335 char *tmpfile
= NULL
;
7337 char *tmpdir
, *mytmpdir
;
7341 assert ( name
!= NULL
);
7344 #define TEMPLATE "pcb.XXXXXXXX"
7347 tmpdir
= getenv ("TMPDIR");
7349 /* FIXME -- what about win32? */
7350 if (tmpdir
== NULL
) {
7354 mytmpdir
= (char *) malloc (sizeof(char) *
7359 if (mytmpdir
== NULL
) {
7360 fprintf (stderr
, "%s(): malloc failed()\n", __FUNCTION__
);
7365 (void)strcat (mytmpdir
, tmpdir
);
7366 (void)strcat (mytmpdir
, PCB_DIR_SEPARATOR_S
);
7367 (void)strcat (mytmpdir
, TEMPLATE
);
7368 if (mkdtemp (mytmpdir
) == NULL
) {
7369 fprintf (stderr
, "%s(): mkdtemp (\"%s\") failed\n", __FUNCTION__
, mytmpdir
);
7375 len
= strlen (mytmpdir
) + /* the temp directory name */
7376 1 + /* the directory sep. */
7377 strlen (name
) + /* the file name */
7378 1 /* the \0 termination */
7381 tmpfile
= (char *) malloc (sizeof (char) * len
);
7384 (void)strcat (tmpfile
, mytmpdir
);
7385 (void)strcat (tmpfile
, PCB_DIR_SEPARATOR_S
);
7386 (void)strcat (tmpfile
, name
);
7392 * tmpnam() uses a static buffer so strdup() the result right away
7393 * in case someone decides to create multiple temp names.
7395 tmpfile
= strdup (tmpnam (NULL
));
7398 /* Guile doesn't like \ separators */
7400 for (c
= tmpfile
; *c
; c
++)
7410 /* ---------------------------------------------------------------- */
7412 * Unlink a temporary file. If we have mkdtemp() then our temp file
7413 * lives in a temporary directory and we need to remove that directory
7417 tempfile_unlink (char * name
)
7420 /* SDB says: Want to keep old temp files for examiniation when debugging */
7429 /* it is possible that the file was never created so it is OK if the
7432 /* now figure out the directory name to remove */
7433 e
= strlen (name
) - 1;
7434 while (e
> 0 && name
[e
] != PCB_DIR_SEPARATOR_C
) {e
--;}
7436 dname
= strdup (name
);
7440 * at this point, e *should* point to the end of the directory part
7441 * but lets make sure.
7444 rc2
= rmdir (dname
);
7450 fprintf (stderr
, _("%s(): Unable to determine temp directory name from the temp file\n"),
7452 fprintf (stderr
, "%s(): \"%s\"\n",
7453 __FUNCTION__
, name
);
7457 /* name was allocated with malloc */
7462 * FIXME - should also return -1 if the temp file exists and was not
7470 int rc
= unlink (name
);
7473 fprintf (stderr
, _("Failed to unlink \"%s\"\n"), name
);
7484 /* ---------------------------------------------------------------- */
7485 static const char import_syntax
[] =
7487 "Import([gnetlist|make[,source,source,...]])\n"
7488 "Import(setnewpoint[,(mark|center|X,Y)])\n"
7489 "Import(setdisperse,D,units)\n");
7491 static const char import_help
[] = N_("Import schematics.");
7493 /* %start-doc actions Import
7495 Imports element and netlist data from the schematics (or some other
7496 source). The first parameter, which is optional, is the mode. If not
7497 specified, the @code{import::mode} attribute in the PCB is used.
7498 @code{gnetlist} means gnetlist is used to obtain the information from
7499 the schematics. @code{make} invokes @code{make}, assuming the user
7500 has a @code{Makefile} in the current directory. The @code{Makefile}
7501 will be invoked with the following variables set:
7506 The name of the .pcb file
7509 A space-separated list of source files
7512 The name of the file in which to put the command script, which may
7513 contain any @pcb{} actions. By default, this is a temporary file
7514 selected by @pcb{}, but if you specify an @code{import::outfile}
7515 attribute, that file name is used instead (and not automatically
7516 deleted afterwards).
7520 The target specified to be built is the first of these that apply:
7525 The target specified by an @code{import::target} attribute.
7528 The output file specified by an @code{import::outfile} attribute.
7531 If nothing else is specified, the target is @code{pcb_import}.
7535 If you specify an @code{import::makefile} attribute, then "-f <that
7536 file>" will be added to the command line.
7538 If you specify the mode, you may also specify the source files
7539 (schematics). If you do not specify any, the list of schematics is
7540 obtained by reading the @code{import::src@var{N}} attributes (like
7541 @code{import::src0}, @code{import::src1}, etc).
7543 For compatibility with future extensions to the import file format,
7544 the generated file @emph{must not} start with the two characters
7547 If a temporary file is needed the @code{TMPDIR} environment variable
7548 is used to select its location.
7550 Note that the programs @code{gnetlist} and @code{make} may be
7551 overridden by the user via the @code{make-program} and @code{gnetlist}
7552 @code{pcb} settings (i.e. in @code{~/.pcb/settings} or on the command
7555 If @pcb{} cannot determine which schematic(s) to import from, the GUI
7556 is called to let user choose (see @code{ImportGUI()}).
7558 Note that Import() doesn't delete anything - after an Import, elements
7559 which shouldn't be on the board are selected and may be removed once
7560 it's determined that the deletion is appropriate.
7562 If @code{Import()} is called with @code{setnewpoint}, then the location
7563 of new components can be specified. This is where parts show up when
7564 they're added to the board. The default is the center of the board.
7568 @item Import(setnewpoint)
7570 Prompts the user to click on the board somewhere, uses that point. If
7571 called by a hotkey, uses the current location of the crosshair.
7573 @item Import(setnewpoint,mark)
7575 Uses the location of the mark. If no mark is present, the point is
7578 @item Import(setnewpoint,center)
7580 Resets the point to the center of the board.
7582 @item Import(setnewpoint,X,Y,units)
7584 Sets the point to the specific coordinates given. Example:
7585 @code{Import(setnewpoint,50,25,mm)}
7589 Note that the X and Y locations are stored in attributes named
7590 @code{import::newX} and @code{import::newY} so you could change them
7591 manually if you wished.
7593 Calling @code{Import(setdisperse,D,units)} sets how much the newly
7594 placed elements are dispersed relative to the set point. For example,
7595 @code{Import(setdisperse,10,mm)} will offset each part randomly up to
7596 10mm away from the point. The default dispersion is 1/10th of the
7597 smallest board dimension. Dispersion is saved in the
7598 @code{import::disperse} attribute.
7603 ActionImport (int argc
, char **argv
, Coord x
, Coord y
)
7606 char **sources
= NULL
;
7610 printf("ActionImport: =========== Entering ActionImport ============\n");
7615 if (mode
&& strcasecmp (mode
, "setdisperse") == 0)
7624 const char *as
= AttributeGet (PCB
, "import::disperse");
7625 ds
= gui
->prompt_for(_("Enter dispersion:"), as
? as
: "0");
7629 sprintf(buf
, "%s%s", ds
, units
);
7630 AttributePut (PCB
, "import::disperse", buf
);
7633 AttributePut (PCB
, "import::disperse", ds
);
7634 if (ARG (1) == NULL
)
7639 if (mode
&& strcasecmp (mode
, "setnewpoint") == 0)
7641 const char *xs
, *ys
, *units
;
7651 gui
->get_coords (_("Click on a location"), &x
, &y
);
7653 else if (strcasecmp (xs
, "center") == 0)
7655 AttributeRemove (PCB
, "import::newX");
7656 AttributeRemove (PCB
, "import::newY");
7659 else if (strcasecmp (xs
, "mark") == 0)
7669 x
= GetValue (xs
, units
, NULL
);
7670 y
= GetValue (ys
, units
, NULL
);
7674 Message (_("Bad syntax for Import(setnewpoint)"));
7678 pcb_sprintf (buf
, "%$ms", x
);
7679 AttributePut (PCB
, "import::newX", buf
);
7680 pcb_sprintf (buf
, "%$ms", y
);
7681 AttributePut (PCB
, "import::newY", buf
);
7686 mode
= AttributeGet (PCB
, "import::mode");
7693 nsources
= argc
- 1;
7704 sprintf(sname
, "import::src%d", nsources
);
7705 src
= AttributeGet (PCB
, sname
);
7710 sources
= (char **) malloc ((nsources
+ 1) * sizeof (char *));
7714 sprintf(sname
, "import::src%d", nsources
);
7715 src
= AttributeGet (PCB
, sname
);
7716 sources
[nsources
] = src
;
7723 /* Replace .pcb with .sch and hope for the best. */
7724 char *pcbname
= PCB
->Filename
;
7726 char *dot
, *slash
, *bslash
;
7729 return hid_action("ImportGUI");
7731 schname
= (char *) malloc (strlen(pcbname
) + 5);
7732 strcpy (schname
, pcbname
);
7733 dot
= strchr (schname
, '.');
7734 slash
= strchr (schname
, '/');
7735 bslash
= strchr (schname
, '\\');
7736 if (dot
&& slash
&& dot
< slash
)
7738 if (dot
&& bslash
&& dot
< bslash
)
7742 strcat (schname
, ".sch");
7744 if (access (schname
, F_OK
))
7747 return hid_action("ImportGUI");
7750 sources
= (char **) malloc (2 * sizeof (char *));
7751 sources
[0] = schname
;
7756 if (strcasecmp (mode
, "gnetlist") == 0)
7758 char *tmpfile
= tempfile_name_new ("gnetlist_output");
7762 if (tmpfile
== NULL
) {
7763 Message (_("Could not create temp file"));
7767 cmd
= (char **) malloc ((7 + nsources
) * sizeof (char *));
7768 cmd
[0] = Settings
.GnetlistProgram
;
7774 for (i
=0; i
<nsources
; i
++)
7775 cmd
[6+i
] = sources
[i
];
7776 cmd
[6+nsources
] = NULL
;
7779 printf("ActionImport: =========== About to run gnetlist ============\n");
7780 printf("%s %s %s %s %s %s %s ...\n",
7781 cmd
[0], cmd
[1], cmd
[2], cmd
[3], cmd
[4], cmd
[5], cmd
[6]);
7784 if (pcb_spawnvp (cmd
))
7791 printf("ActionImport: =========== About to run ActionExecuteFile, file = %s ============\n", tmpfile
);
7796 ActionExecuteFile (1, cmd
, 0, 0);
7799 tempfile_unlink (tmpfile
);
7801 else if (strcasecmp (mode
, "make") == 0)
7803 int must_free_tmpfile
= 0;
7809 char *user_outfile
= NULL
;
7810 char *user_makefile
= NULL
;
7811 char *user_target
= NULL
;
7814 user_outfile
= AttributeGet (PCB
, "import::outfile");
7815 user_makefile
= AttributeGet (PCB
, "import::makefile");
7816 user_target
= AttributeGet (PCB
, "import::target");
7817 if (user_outfile
&& !user_target
)
7818 user_target
= user_outfile
;
7821 tmpfile
= user_outfile
;
7824 tmpfile
= tempfile_name_new ("gnetlist_output");
7825 if (tmpfile
== NULL
) {
7826 Message (_("Could not create temp file"));
7829 must_free_tmpfile
= 1;
7832 srclen
= sizeof("SRCLIST=") + 2;
7833 for (i
=0; i
<nsources
; i
++)
7834 srclen
+= strlen (sources
[i
]) + 2;
7835 srclist
= (char *) malloc (srclen
);
7836 strcpy (srclist
, "SRCLIST=");
7837 for (i
=0; i
<nsources
; i
++)
7840 strcat (srclist
, " ");
7841 strcat (srclist
, sources
[i
]);
7844 cmd
[0] = Settings
.MakeProgram
;
7846 cmd
[2] = Concat ("PCB=", PCB
->Filename
, NULL
);
7848 cmd
[4] = Concat ("OUT=", tmpfile
, NULL
);
7853 cmd
[i
++] = user_makefile
;
7855 cmd
[i
++] = user_target
? user_target
: (char *)"pcb_import";
7858 if (pcb_spawnvp (cmd
))
7860 if (must_free_tmpfile
)
7870 ActionExecuteFile (1, cmd
, 0, 0);
7875 if (must_free_tmpfile
)
7876 tempfile_unlink (tmpfile
);
7880 Message (_("Unknown import mode: %s\n"), mode
);
7885 AddAllRats (false, NULL
);
7888 printf("ActionImport: =========== Leaving ActionImport ============\n");
7894 /* ------------------------------------------------------------ */
7896 static const char attributes_syntax
[] =
7897 N_("Attributes(Layout|Layer|Element)\n"
7898 "Attributes(Layer,layername)");
7900 static const char attributes_help
[] =
7901 N_("Let the user edit the attributes of the layout, current or given\n"
7902 "layer, or selected element.");
7904 /* %start-doc actions Attributes
7906 This just pops up a dialog letting the user edit the attributes of the
7907 pcb, an element, or a layer.
7913 ActionAttributes (int argc
, char **argv
, Coord x
, Coord y
)
7915 char *function
= ARG (0);
7916 char *layername
= ARG (1);
7922 if (!gui
->edit_attributes
)
7924 Message (_("This GUI doesn't support Attribute Editing\n"));
7928 switch (GetFunctionID (function
))
7932 gui
->edit_attributes(_("Layout Attributes"), &(PCB
->Attributes
));
7938 LayerType
*layer
= CURRENT
;
7943 for (i
=0; i
<max_copper_layer
; i
++)
7944 if (strcmp (PCB
->Data
->Layer
[i
].Name
, layername
) == 0)
7946 layer
= & (PCB
->Data
->Layer
[i
]);
7951 Message (_("No layer named %s\n"), layername
);
7955 buf
= (char *) malloc (strlen (layer
->Name
) +
7956 strlen (_("Layer %s Attributes")));
7957 sprintf (buf
, _("Layer %s Attributes"), layer
->Name
);
7958 gui
->edit_attributes(buf
, &(layer
->Attributes
));
7966 ElementType
*e
= NULL
;
7967 ELEMENT_LOOP (PCB
->Data
);
7969 if (TEST_FLAG (SELECTEDFLAG
, element
))
7978 Message (_("Too many elements selected\n"));
7984 gui
->get_coords (_("Click on an element"), &x
, &y
);
7986 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
7987 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
7988 e
= (ElementType
*) ptrtmp
;
7991 Message (_("No element found there\n"));
7996 if (NAMEONPCB_NAME(e
))
7998 buf
= (char *) malloc (strlen (NAMEONPCB_NAME(e
)) +
7999 strlen (_("Element %s Attributes")));
8000 sprintf(buf
, _("Element %s Attributes"), NAMEONPCB_NAME(e
));
8004 buf
= strdup (_("Unnamed Element Attributes"));
8006 gui
->edit_attributes(buf
, &(e
->Attributes
));
8018 /* --------------------------------------------------------------------------- */
8020 HID_Action action_action_list
[] = {
8021 {"AddRats", 0, ActionAddRats
,
8022 addrats_help
, addrats_syntax
}
8024 {"Attributes", 0, ActionAttributes
,
8025 attributes_help
, attributes_syntax
}
8027 {"Atomic", 0, ActionAtomic
,
8028 atomic_help
, atomic_syntax
}
8030 {"AutoPlaceSelected", 0, ActionAutoPlaceSelected
,
8031 autoplace_help
, autoplace_syntax
}
8033 {"AutoRoute", 0, ActionAutoRoute
,
8034 autoroute_help
, autoroute_syntax
}
8036 {"ChangeClearSize", 0, ActionChangeClearSize
,
8037 changeclearsize_help
, changeclearsize_syntax
}
8039 {"ChangeDrillSize", 0, ActionChange2ndSize
,
8040 changedrillsize_help
, changedrillsize_syntax
}
8042 {"ChangeHole", 0, ActionChangeHole
,
8043 changehold_help
, changehold_syntax
}
8045 {"ChangeJoin", 0, ActionChangeJoin
,
8046 changejoin_help
, changejoin_syntax
}
8048 {"ChangeName", 0, ActionChangeName
,
8049 changename_help
, changename_syntax
}
8051 {"ChangePaste", 0, ActionChangePaste
,
8052 changepaste_help
, changepaste_syntax
}
8054 {"ChangePinName", 0, ActionChangePinName
,
8055 changepinname_help
, changepinname_syntax
}
8057 {"ChangeSize", 0, ActionChangeSize
,
8058 changesize_help
, changesize_syntax
}
8060 {"ChangeSquare", 0, ActionChangeSquare
,
8061 changesquare_help
, changesquare_syntax
}
8063 {"ChangeOctagon", 0, ActionChangeOctagon
,
8064 changeoctagon_help
, changeoctagon_syntax
}
8066 {"ClearSquare", 0, ActionClearSquare
,
8067 clearsquare_help
, clearsquare_syntax
}
8069 {"ClearOctagon", 0, ActionClearOctagon
,
8070 clearoctagon_help
, clearoctagon_syntax
}
8072 {"Connection", 0, ActionConnection
,
8073 connection_help
, connection_syntax
}
8075 {"Delete", 0, ActionDelete
,
8076 delete_help
, delete_syntax
}
8078 {"DeleteRats", 0, ActionDeleteRats
,
8079 deleterats_help
, deleterats_syntax
}
8081 {"DisperseElements", 0, ActionDisperseElements
,
8082 disperseelements_help
, disperseelements_syntax
}
8084 {"Display", 0, ActionDisplay
,
8085 display_help
, display_syntax
}
8087 {"DRC", 0, ActionDRCheck
,
8088 drc_help
, drc_syntax
}
8090 {"DumpLibrary", 0, ActionDumpLibrary
,
8091 dumplibrary_help
, dumplibrary_syntax
}
8093 {"ExecuteFile", 0, ActionExecuteFile
,
8094 executefile_help
, executefile_syntax
}
8096 {"Flip", N_("Click on Object or Flip Point"), ActionFlip
,
8097 flip_help
, flip_syntax
}
8099 {"LoadFrom", 0, ActionLoadFrom
,
8100 loadfrom_help
, loadfrom_syntax
}
8102 {"MarkCrosshair", 0, ActionMarkCrosshair
,
8103 markcrosshair_help
, markcrosshair_syntax
}
8105 {"Message", 0, ActionMessage
,
8106 message_help
, message_syntax
}
8108 {"MinMaskGap", 0, ActionMinMaskGap
,
8109 minmaskgap_help
, minmaskgap_syntax
}
8111 {"MinClearGap", 0, ActionMinClearGap
,
8112 mincleargap_help
, mincleargap_syntax
}
8114 {"Mode", 0, ActionMode
,
8115 mode_help
, mode_syntax
}
8117 {"MorphPolygon", 0, ActionMorphPolygon
,
8118 morphpolygon_help
, morphpolygon_syntax
}
8120 {"PasteBuffer", 0, ActionPasteBuffer
,
8121 pastebuffer_help
, pastebuffer_syntax
}
8123 {"Quit", 0, ActionQuit
,
8124 quit_help
, quit_syntax
}
8126 {"RemoveSelected", 0, ActionRemoveSelected
,
8127 removeselected_help
, removeselected_syntax
}
8129 {"Renumber", 0, ActionRenumber
,
8130 renumber_help
, renumber_syntax
}
8132 {"RipUp", 0, ActionRipUp
,
8133 ripup_help
, ripup_syntax
}
8135 {"Select", 0, ActionSelect
,
8136 select_help
, select_syntax
}
8138 {"Unselect", 0, ActionUnselect
,
8139 unselect_help
, unselect_syntax
}
8141 {"SaveSettings", 0, ActionSaveSettings
,
8142 savesettings_help
, savesettings_syntax
}
8144 {"SaveTo", 0, ActionSaveTo
,
8145 saveto_help
, saveto_syntax
}
8147 {"SetSquare", 0, ActionSetSquare
,
8148 setsquare_help
, setsquare_syntax
}
8150 {"SetOctagon", 0, ActionSetOctagon
,
8151 setoctagon_help
, setoctagon_syntax
}
8153 {"SetThermal", 0, ActionSetThermal
,
8154 setthermal_help
, setthermal_syntax
}
8156 {"SetValue", 0, ActionSetValue
,
8157 setvalue_help
, setvalue_syntax
}
8159 {"ToggleHideName", 0, ActionToggleHideName
,
8160 togglehidename_help
, togglehidename_syntax
}
8162 {"Undo", 0, ActionUndo
,
8163 undo_help
, undo_syntax
}
8165 {"Redo", 0, ActionRedo
,
8166 redo_help
, redo_syntax
}
8168 {"SetSame", N_("Select item to use attributes from"), ActionSetSame
,
8169 setsame_help
, setsame_syntax
}
8171 {"SetFlag", 0, ActionSetFlag
,
8172 setflag_help
, setflag_syntax
}
8174 {"ClrFlag", 0, ActionClrFlag
,
8175 clrflag_help
, clrflag_syntax
}
8177 {"ChangeFlag", 0, ActionChangeFlag
,
8178 changeflag_help
, changeflag_syntax
}
8180 {"Polygon", 0, ActionPolygon
,
8181 polygon_help
, polygon_syntax
}
8183 {"RouteStyle", 0, ActionRouteStyle
,
8184 routestyle_help
, routestyle_syntax
}
8186 {"MoveObject", N_("Select an Object"), ActionMoveObject
,
8187 moveobject_help
, moveobject_syntax
}
8189 {"MoveToCurrentLayer", 0, ActionMoveToCurrentLayer
,
8190 movetocurrentlayer_help
, movetocurrentlayer_syntax
}
8192 {"New", 0, ActionNew
,
8193 new_help
, new_syntax
}
8195 {"pscalib", 0, ActionPSCalib
}
8197 {"ElementList", 0, ActionElementList
,
8198 elementlist_help
, elementlist_syntax
}
8200 {"ElementSetAttr", 0, ActionElementSetAttr
,
8201 elementsetattr_help
, elementsetattr_syntax
}
8203 {"ExecCommand", 0, ActionExecCommand
,
8204 execcommand_help
, execcommand_syntax
}
8206 {"Import", 0, ActionImport
,
8207 import_help
, import_syntax
}
8211 REGISTER_ACTIONS (action_action_list
)