4 * \brief Action routines for output window.
8 * <h1><b>Copyright.</b></h1>\n
10 * PCB, interactive printed circuit board design
12 * Copyright (C) 1994,1995,1996 Thomas Nau
14 * Copyright (C) 1997, 1998, 1999, 2000, 2001 Harry Eaton
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 * Contact addresses for paper mail and Email:
31 * Harry Eaton, 6697 Buttonhole Ct, Columbia, MD 21044, USA
32 * haceaton@aplcomm.jhuapl.edu
42 #include "autoplace.h"
43 #include "autoroute.h"
48 #include "crosshair.h"
62 /*#include "print.h"*/
67 #include "rubberband.h"
75 #include "pcb-printf.h"
78 #include <stdlib.h> /* rand() */
80 #ifdef HAVE_LIBDMALLOC
84 /* for fork() and friends */
89 #ifdef HAVE_SYS_WAIT_H
93 /* ---------------------------------------------------------------------------
124 F_ElementConnections
,
165 F_ResetLinesAndPolygons
,
166 F_ResetPinsViasAndPads
,
187 F_ToggleAllDirections
,
198 F_ToggleRubberBandMode
,
199 F_ToggleStartDirection
,
204 F_ToggleThindrawPoly
,
218 typedef struct /* used to identify subfunctions */
225 /* --------------------------------------------------------------------------- */
227 /* %start-doc actions 00delta
229 Many actions take a @code{delta} parameter as the last parameter,
230 which is an amount to change something. That @code{delta} may include
231 units, as an additional parameter, such as @code{Action(Object,5,mm)}.
232 If no units are specified, the default is PCB's native units
233 (currently 1/100 mil). Also, if the delta is prefixed by @code{+} or
234 @code{-}, the size is increased or decreased by that amount.
235 Otherwise, the size size is set to the given amount.
239 Action(Object,+0.5,mm)
243 Actions which take a @code{delta} parameter which do not accept all
244 these options will specify what they do take.
248 /* %start-doc actions 00objects
250 Many actions act on indicated objects on the board. They will have
251 parameters like @code{ToggleObject} or @code{SelectedVias} to indicate
252 what group of objects they act on. Unless otherwise specified, these
253 parameters are defined as follows:
259 Affects the object under the mouse pointer. If this action is invoked
260 from a menu or script, the user will be prompted to click on an
261 object, which is then the object affected.
264 @itemx SelectedObjects
266 Affects all objects which are currently selected. At least, all
267 selected objects for which the given action makes sense.
271 @itemx Selected@var{Type}
273 Affects all objects which are both selected and of the @var{Type} specified.
279 /* %start-doc actions 00macros
283 Pins, pads, and vias can have various shapes. All may be round. Pins
284 and pads may be square (obviously "square" pads are usually
285 rectangular). Pins and vias may be octagonal. When you change a
286 shape flag of an element, you actually change all of its pins and
289 Note that the square flag takes precedence over the octagon flag,
290 thus, if both the square and octagon flags are set, the object is
291 square. When the square flag is cleared, the pins and pads will be
292 either round or, if the octagon flag is set, octagonal.
298 /* ---------------------------------------------------------------------------
299 * some local identifiers
301 static PointType InsertedPoint
;
302 static LayerType
*lastLayer
;
315 bool Moving
; /* selected type clicked on */
316 int Hit
; /* move type clicked on */
323 static int defer_updates
= 0;
324 static int defer_needs_update
= 0;
326 static Cardinal polyIndex
= 0;
327 static bool saved_mode
= false;
328 #ifdef HAVE_LIBSTROKE
329 static bool mid_stroke
= false;
330 static BoxType StrokeBox
;
332 static FunctionType Functions
[] = {
333 {"AddSelected", F_AddSelected
},
335 {"AllConnections", F_AllConnections
},
336 {"AllRats", F_AllRats
},
337 {"AllUnusedPins", F_AllUnusedPins
},
341 {"Description", F_Description
},
342 {"Cancel", F_Cancel
},
343 {"Center", F_Center
},
345 {"ClearAndRedraw", F_ClearAndRedraw
},
346 {"ClearList", F_ClearList
},
349 {"Connection", F_Connection
},
350 {"Convert", F_Convert
},
352 {"CycleClip", F_CycleClip
},
353 {"CycleCrosshair", F_CycleCrosshair
},
354 {"DeleteRats", F_DeleteRats
},
356 {"DrillReport", F_DrillReport
},
357 {"Element", F_Element
},
358 {"ElementByName", F_ElementByName
},
359 {"ElementConnections", F_ElementConnections
},
360 {"ElementToBuffer", F_ElementToBuffer
},
361 {"Escape", F_Escape
},
363 {"FlipElement", F_FlipElement
},
364 {"FoundPins", F_FoundPins
},
366 {"InsertPoint", F_InsertPoint
},
368 {"Layout", F_Layout
},
369 {"LayoutAs", F_LayoutAs
},
370 {"LayoutToBuffer", F_LayoutToBuffer
},
372 {"LineSize", F_LineSize
},
374 {"Mirror", F_Mirror
},
376 {"NameOnPCB", F_NameOnPCB
},
377 {"Netlist", F_Netlist
},
378 {"NetByName", F_NetByName
},
380 {"Notify", F_Notify
},
381 {"Object", F_Object
},
382 {"ObjectByName", F_ObjectByName
},
383 {"PasteBuffer", F_PasteBuffer
},
384 {"PadByName", F_PadByName
},
385 {"PinByName", F_PinByName
},
386 {"PinOrPadName", F_PinOrPadName
},
387 {"Pinout", F_Pinout
},
388 {"Polygon", F_Polygon
},
389 {"PolygonHole", F_PolygonHole
},
390 {"PreviousPoint", F_PreviousPoint
},
391 {"RatsNest", F_RatsNest
},
392 {"Rectangle", F_Rectangle
},
393 {"Redraw", F_Redraw
},
394 {"Release", F_Release
},
395 {"Remove", F_Remove
},
396 {"RemoveSelected", F_RemoveSelected
},
397 {"Report", F_Report
},
399 {"ResetLinesAndPolygons", F_ResetLinesAndPolygons
},
400 {"ResetPinsViasAndPads", F_ResetPinsViasAndPads
},
401 {"Restore", F_Restore
},
402 {"Revert", F_Revert
},
403 {"Rotate", F_Rotate
},
405 {"Selected", F_Selected
},
406 {"SelectedArcs", F_SelectedArcs
},
407 {"SelectedElements", F_SelectedElements
},
408 {"SelectedLines", F_SelectedLines
},
409 {"SelectedNames", F_SelectedNames
},
410 {"SelectedObjects", F_SelectedObjects
},
411 {"SelectedPins", F_SelectedPins
},
412 {"SelectedPads", F_SelectedPads
},
413 {"SelectedRats", F_SelectedRats
},
414 {"SelectedTexts", F_SelectedTexts
},
415 {"SelectedVias", F_SelectedVias
},
416 {"Stroke", F_Stroke
},
418 {"TextByName", F_TextByName
},
419 {"TextScale", F_TextScale
},
420 {"Thermal", F_Thermal
},
421 {"ToLayout", F_ToLayout
},
422 {"Toggle45Degree", F_ToggleAllDirections
},
423 {"ToggleClearLine", F_ToggleClearLine
},
424 {"ToggleFullPoly", F_ToggleFullPoly
},
425 {"ToggleGrid", F_ToggleGrid
},
426 {"ToggleMask", F_ToggleMask
},
427 {"ToggleName", F_ToggleName
},
428 {"ToggleObject", F_ToggleObject
},
429 {"ToggleRubberBandMode", F_ToggleRubberBandMode
},
430 {"ToggleStartDirection", F_ToggleStartDirection
},
431 {"ToggleSnapPin", F_ToggleSnapPin
},
432 {"ToggleThindraw", F_ToggleThindraw
},
433 {"ToggleThindrawPoly", F_ToggleThindrawPoly
},
434 {"ToggleLockNames", F_ToggleLockNames
},
435 {"ToggleOnlyNames", F_ToggleOnlyNames
},
436 {"ToggleHideNames", F_ToggleHideNames
},
437 {"ToggleCheckPlanes", F_ToggleCheckPlanes
},
438 {"ToggleLocalRef", F_ToggleLocalRef
},
439 {"ToggleOrthoMove", F_ToggleOrthoMove
},
440 {"ToggleShowDRC", F_ToggleShowDRC
},
441 {"ToggleLiveRoute", F_ToggleLiveRoute
},
442 {"ToggleAutoDRC", F_ToggleAutoDRC
},
443 {"ToggleUniqueNames", F_ToggleUniqueNames
},
446 {"ViaByName", F_ViaByName
},
447 {"ViaSize", F_ViaSize
},
448 {"ViaDrillingHole", F_ViaDrillingHole
},
452 /* ---------------------------------------------------------------------------
453 * some local routines
455 static int GetFunctionID (String
);
456 static void AdjustAttachedBox (void);
457 static void NotifyLine (void);
458 static void NotifyBlock (void);
459 static void NotifyMode (void);
460 static void ClearWarnings (void);
461 #ifdef HAVE_LIBSTROKE
462 static void FinishStroke (void);
463 extern void stroke_init (void);
464 extern void stroke_record (int x
, int y
);
465 extern int stroke_trans (char *s
);
467 static void ChangeFlag (char *, char *, int, char *);
469 #define ARG(n) (argc > (n) ? argv[n] : NULL)
471 #ifdef HAVE_LIBSTROKE
474 * \brief Try to recognize the stroke sent.
482 void *ptr1
, *ptr2
, *ptr3
;
485 if (stroke_trans (msg
))
491 if (Settings
.Mode
== LINE_MODE
)
501 RotateScreenObject (StrokeBox
.X1
, StrokeBox
.Y1
, SWAP_IDENT
? 1 : 3);
507 RotateScreenObject (StrokeBox
.X1
, StrokeBox
.Y1
, SWAP_IDENT
? 3 : 1);
513 SetMode (ARROW_MODE
);
538 /* XXX: FIXME: Call a zoom-extents action */
549 /* XXX: FIXME: Zoom to fit the box StrokeBox.[X1,Y1] - StrokeBox.[X2,Y2] */
553 Message (_("Unknown stroke %s\n"), msg
);
563 * \brief Clear warning color from pins/pads.
568 Settings
.RatWarn
= false;
569 ALLPIN_LOOP (PCB
->Data
);
571 if (TEST_FLAG (WARNFLAG
, pin
))
573 CLEAR_FLAG (WARNFLAG
, pin
);
578 ALLPAD_LOOP (PCB
->Data
);
580 if (TEST_FLAG (WARNFLAG
, pad
))
582 CLEAR_FLAG (WARNFLAG
, pad
);
591 * \brief Click callback.
593 * This is called a clicktime after a mouse down, to we can distinguish
594 * between short clicks (typically: select or create something) and long
595 * clicks. Long clicks typically drag something.
602 notify_crosshair_change (false);
604 if (Note
.Moving
&& !gui
->shift_is_pressed ())
606 Note
.Buffer
= Settings
.BufferNumber
;
607 SetBufferNumber (MAX_BUFFER
- 1);
608 ClearBuffer (PASTEBUFFER
);
609 AddSelectedToBuffer (PASTEBUFFER
, Note
.X
, Note
.Y
, true);
610 SaveUndoSerialNumber ();
614 SetMode (PASTEBUFFER_MODE
);
616 else if (Note
.Hit
&& !gui
->shift_is_pressed ())
620 SetMode (gui
->control_is_pressed ()? COPY_MODE
: MOVE_MODE
);
621 Crosshair
.AttachedObject
.Ptr1
= Note
.ptr1
;
622 Crosshair
.AttachedObject
.Ptr2
= Note
.ptr2
;
623 Crosshair
.AttachedObject
.Ptr3
= Note
.ptr3
;
624 Crosshair
.AttachedObject
.Type
= Note
.Hit
;
625 AttachForCopy (Note
.X
, Note
.Y
);
633 SaveUndoSerialNumber ();
638 /* unselect first if shift key not down */
639 if (!gui
->shift_is_pressed () && SelectBlock (&box
, false))
640 SetChangedFlag (true);
642 Crosshair
.AttachedBox
.Point1
.X
= Note
.X
;
643 Crosshair
.AttachedBox
.Point1
.Y
= Note
.Y
;
645 notify_crosshair_change (true);
650 * \brief This is typically called when the mouse has moved or the mouse
651 * button was released.
667 Note
.Click
= false; /* inhibit timer action */
668 SaveUndoSerialNumber ();
669 /* unselect first if shift key not down */
670 if (!gui
->shift_is_pressed ())
672 if (SelectBlock (&box
, false))
673 SetChangedFlag (true);
681 /* Restore the SN so that if we select something the deselect/select combo
683 RestoreUndoSerialNumber();
685 SetChangedFlag (true);
687 /* We didn't select anything new, so, the deselection should get its
689 IncrementUndoSerialNumber();
693 else if (Note
.Moving
)
695 RestoreUndoSerialNumber ();
697 ClearBuffer (PASTEBUFFER
);
698 SetBufferNumber (Note
.Buffer
);
707 else if (Settings
.Mode
== ARROW_MODE
)
709 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
710 Crosshair
.AttachedBox
.Point2
.X
);
711 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
712 Crosshair
.AttachedBox
.Point2
.Y
);
713 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
714 Crosshair
.AttachedBox
.Point2
.X
);
715 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
716 Crosshair
.AttachedBox
.Point2
.Y
);
717 RestoreUndoSerialNumber ();
718 if (SelectBlock (&box
, true))
719 SetChangedFlag (true);
721 IncrementUndoSerialNumber ();
722 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
730 static char function_hash
[HSIZE
];
731 static int hash_initted
= 0;
740 i
= (i
* 13) ^ (unsigned char)tolower((int) *s
);
743 i
= (unsigned int)i
% HSIZE
;
748 * \brief Get function ID of passed string.
751 GetFunctionID (String Ident
)
761 if (HSIZE
< ENTRIES (Functions
) * 2)
763 fprintf(stderr
, _("Error: function hash size too small (%d vs %lu at %s:%d)\n"),
764 HSIZE
, (unsigned long) ENTRIES (Functions
)*2, __FILE__
, __LINE__
);
767 if (ENTRIES (Functions
) > 254)
769 /* Change 'char' to 'int' and remove this when we get to 256
771 fprintf(stderr
, _("Error: function hash type too small (%d vs %lu at %s:%d)\n"),
772 256, (unsigned long) ENTRIES (Functions
), __FILE__
, __LINE__
);
776 for (i
=ENTRIES (Functions
)-1; i
>=0; i
--)
778 h
= hashfunc (Functions
[i
].Identifier
);
779 while (function_hash
[h
])
781 function_hash
[h
] = i
+ 1;
785 i
= hashfunc (Ident
);
788 /* We enforce the "hash table bigger than function table" rule,
789 so we know there will be at least one zero entry to find. */
790 if (!function_hash
[i
])
792 if (!strcasecmp (Ident
, Functions
[function_hash
[i
]-1].Identifier
))
793 return ((int) Functions
[function_hash
[i
]-1].ID
);
799 * \brief Set new coordinates if in 'RECTANGLE' mode.
801 * The cursor shape is also adjusted.
804 AdjustAttachedBox (void)
806 if (Settings
.Mode
== ARC_MODE
)
808 Crosshair
.AttachedBox
.otherway
= gui
->shift_is_pressed ();
811 switch (Crosshair
.AttachedBox
.State
)
813 case STATE_SECOND
: /* one corner is selected */
815 /* update coordinates */
816 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
817 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
824 * \brief Adjusts the objects which are to be created like attached
828 AdjustAttachedObjects (void)
831 switch (Settings
.Mode
)
833 /* update at least an attached block (selection) */
836 if (Crosshair
.AttachedBox
.State
)
838 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
839 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
843 /* rectangle creation mode */
846 AdjustAttachedBox ();
849 /* polygon creation mode */
851 case POLYGONHOLE_MODE
:
852 AdjustAttachedLine ();
854 /* line creation mode */
856 if (PCB
->RatDraw
|| PCB
->Clipping
== 0)
857 AdjustAttachedLine ();
859 AdjustTwoLine (PCB
->Clipping
- 1);
861 /* point insertion mode */
862 case INSERTPOINT_MODE
:
863 pnt
= AdjustInsertPoint ();
865 InsertedPoint
= *pnt
;
873 * \brief Creates points of a line.
879 void *ptr1
, *ptr2
, *ptr3
;
881 if (!Marked
.status
|| TEST_FLAG (LOCALREFFLAG
, PCB
))
882 SetLocalRef (Crosshair
.X
, Crosshair
.Y
, true);
883 switch (Crosshair
.AttachedLine
.State
)
885 case STATE_FIRST
: /* first point */
886 if (PCB
->RatDraw
&& SearchScreen (Crosshair
.X
, Crosshair
.Y
,
887 PAD_TYPE
| PIN_TYPE
, &ptr1
, &ptr1
,
893 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
895 type
= SearchScreen (Crosshair
.X
, Crosshair
.Y
,
896 PIN_TYPE
| PAD_TYPE
| VIA_TYPE
, &ptr1
, &ptr2
,
898 LookupConnection (Crosshair
.X
, Crosshair
.Y
, true, 1, CONNECTEDFLAG
, false);
899 LookupConnection (Crosshair
.X
, Crosshair
.Y
, true, 1, FOUNDFLAG
, true);
901 if (type
== PIN_TYPE
|| type
== VIA_TYPE
)
903 Crosshair
.AttachedLine
.Point1
.X
=
904 Crosshair
.AttachedLine
.Point2
.X
= ((PinType
*) ptr2
)->X
;
905 Crosshair
.AttachedLine
.Point1
.Y
=
906 Crosshair
.AttachedLine
.Point2
.Y
= ((PinType
*) ptr2
)->Y
;
908 else if (type
== PAD_TYPE
)
910 PadType
*pad
= (PadType
*) ptr2
;
911 double d1
= Distance (Crosshair
.X
, Crosshair
.Y
, pad
->Point1
.X
, pad
->Point1
.Y
);
912 double d2
= Distance (Crosshair
.X
, Crosshair
.Y
, pad
->Point2
.X
, pad
->Point2
.Y
);
915 Crosshair
.AttachedLine
.Point1
=
916 Crosshair
.AttachedLine
.Point2
= pad
->Point2
;
920 Crosshair
.AttachedLine
.Point1
=
921 Crosshair
.AttachedLine
.Point2
= pad
->Point1
;
926 Crosshair
.AttachedLine
.Point1
.X
=
927 Crosshair
.AttachedLine
.Point2
.X
= Crosshair
.X
;
928 Crosshair
.AttachedLine
.Point1
.Y
=
929 Crosshair
.AttachedLine
.Point2
.Y
= Crosshair
.Y
;
931 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
935 /* fall through to third state too */
937 default: /* all following points */
938 Crosshair
.AttachedLine
.State
= STATE_THIRD
;
944 * \brief Create first or second corner of a marked block.
949 notify_crosshair_change (false);
950 switch (Crosshair
.AttachedBox
.State
)
952 case STATE_FIRST
: /* setup first point */
953 Crosshair
.AttachedBox
.Point1
.X
=
954 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
955 Crosshair
.AttachedBox
.Point1
.Y
=
956 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
957 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
960 case STATE_SECOND
: /* setup second point */
961 Crosshair
.AttachedBox
.State
= STATE_THIRD
;
964 notify_crosshair_change (true);
969 * \brief This is called after every mode change, like mouse button pressed,
970 * mouse button released, dragging something started or a different tool
973 * It does what's appropriate for the current mode setting.
974 * This can also mean creation of an object at the current crosshair location.
976 * New created objects are added to the create undo list of course.
981 void *ptr1
, *ptr2
, *ptr3
;
984 if (Settings
.RatWarn
)
986 switch (Settings
.Mode
)
994 /* do something after click time */
995 gui
->add_timer (click_cb
, CLICK_TIME
, hv
);
997 /* see if we clicked on something already selected
998 * (Note.Moving) or clicked on a MOVE_TYPE
1001 for (test
= (SELECT_TYPES
| MOVE_TYPES
) & ~RATLINE_TYPE
;
1002 test
; test
&= ~type
)
1004 type
= SearchScreen (Note
.X
, Note
.Y
, test
, &ptr1
, &ptr2
, &ptr3
);
1005 if (!Note
.Hit
&& (type
& MOVE_TYPES
) &&
1006 !TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
1013 if (!Note
.Moving
&& (type
& SELECT_TYPES
) &&
1014 TEST_FLAG (SELECTEDFLAG
, (PinType
*) ptr2
))
1016 if ((Note
.Hit
&& Note
.Moving
) || type
== NO_TYPE
)
1028 Message (_("You must turn via visibility on before\n"
1029 "you can place vias\n"));
1032 if ((via
= CreateNewVia (PCB
->Data
, Note
.X
, Note
.Y
,
1033 Settings
.ViaThickness
, 2 * Settings
.Keepaway
,
1034 0, Settings
.ViaDrillingHole
, NULL
,
1035 NoFlags ())) != NULL
)
1037 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1038 if (gui
->shift_is_pressed ())
1039 ChangeObjectThermal (VIA_TYPE
, via
, via
, via
, PCB
->ThermStyle
);
1040 IncrementUndoSerialNumber ();
1049 switch (Crosshair
.AttachedBox
.State
)
1052 Crosshair
.AttachedBox
.Point1
.X
=
1053 Crosshair
.AttachedBox
.Point2
.X
= Note
.X
;
1054 Crosshair
.AttachedBox
.Point1
.Y
=
1055 Crosshair
.AttachedBox
.Point2
.Y
= Note
.Y
;
1056 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
1066 wx
= Note
.X
- Crosshair
.AttachedBox
.Point1
.X
;
1067 wy
= Note
.Y
- Crosshair
.AttachedBox
.Point1
.Y
;
1068 if (XOR (Crosshair
.AttachedBox
.otherway
, abs (wy
) > abs (wx
)))
1070 Crosshair
.AttachedBox
.Point2
.X
=
1071 Crosshair
.AttachedBox
.Point1
.X
+ abs (wy
) * SGNZ (wx
);
1072 sa
= (wx
>= 0) ? 0 : 180;
1074 if (abs (wy
) / 2 >= abs (wx
))
1075 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 45 : -45;
1078 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 90 : -90;
1082 Crosshair
.AttachedBox
.Point2
.Y
=
1083 Crosshair
.AttachedBox
.Point1
.Y
+ abs (wx
) * SGNZ (wy
);
1084 sa
= (wy
>= 0) ? -90 : 90;
1086 if (abs (wx
) / 2 >= abs (wy
))
1087 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -45 : 45;
1090 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -90 : 90;
1093 if (abs (wy
) > 0 && (arc
= CreateNewArcOnLayer (CURRENT
,
1117 bx
= GetArcEnds (arc
);
1118 Crosshair
.AttachedBox
.Point1
.X
=
1119 Crosshair
.AttachedBox
.Point2
.X
= bx
->X2
;
1120 Crosshair
.AttachedBox
.Point1
.Y
=
1121 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y2
;
1122 AddObjectToCreateUndoList (ARC_TYPE
, CURRENT
, arc
, arc
);
1123 IncrementUndoSerialNumber ();
1125 DrawArc (CURRENT
, arc
);
1127 Crosshair
.AttachedBox
.State
= STATE_THIRD
;
1136 type
= SearchScreen (Note
.X
, Note
.Y
, LOCK_TYPES
, &ptr1
, &ptr2
, &ptr3
);
1137 if (type
== ELEMENT_TYPE
)
1139 ElementType
*element
= (ElementType
*) ptr2
;
1141 TOGGLE_FLAG (LOCKFLAG
, element
);
1144 TOGGLE_FLAG (LOCKFLAG
, pin
);
1145 CLEAR_FLAG (SELECTEDFLAG
, pin
);
1150 TOGGLE_FLAG (LOCKFLAG
, pad
);
1151 CLEAR_FLAG (SELECTEDFLAG
, pad
);
1154 CLEAR_FLAG (SELECTEDFLAG
, element
);
1155 /* always re-draw it since I'm too lazy
1156 * to tell if a selected flag changed
1158 DrawElement (element
);
1160 SetChangedFlag (true);
1161 hid_actionl ("Report", "Object", NULL
);
1163 else if (type
!= NO_TYPE
)
1165 TextType
*thing
= (TextType
*) ptr3
;
1166 TOGGLE_FLAG (LOCKFLAG
, thing
);
1167 if (TEST_FLAG (LOCKFLAG
, thing
)
1168 && TEST_FLAG (SELECTEDFLAG
, thing
))
1170 /* this is not un-doable since LOCK isn't */
1171 CLEAR_FLAG (SELECTEDFLAG
, thing
);
1172 DrawObject (type
, ptr1
, ptr2
);
1175 SetChangedFlag (true);
1176 hid_actionl ("Report", "Object", NULL
);
1184 SearchScreen (Note
.X
, Note
.Y
, PIN_TYPES
, &ptr1
, &ptr2
,
1186 && !TEST_FLAG (HOLEFLAG
, (PinType
*) ptr3
))
1188 if (gui
->shift_is_pressed ())
1190 int tstyle
= GET_THERM (INDEXOFCURRENT
, (PinType
*) ptr3
);
1194 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, tstyle
);
1196 else if (GET_THERM (INDEXOFCURRENT
, (PinType
*) ptr3
))
1197 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, 0);
1199 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, PCB
->ThermStyle
);
1205 /* do update of position */
1207 if (Crosshair
.AttachedLine
.State
!= STATE_THIRD
)
1210 /* Remove anchor if clicking on start point;
1211 * this means we can't paint 0 length lines
1212 * which could be used for square SMD pads.
1213 * Instead use a very small delta, or change
1214 * the file after saving.
1216 if (Crosshair
.X
== Crosshair
.AttachedLine
.Point1
.X
1217 && Crosshair
.Y
== Crosshair
.AttachedLine
.Point1
.Y
)
1219 SetMode (LINE_MODE
);
1226 if ((line
= AddNet ()))
1229 AddObjectToCreateUndoList (RATLINE_TYPE
, line
, line
, line
);
1230 IncrementUndoSerialNumber ();
1232 Crosshair
.AttachedLine
.Point1
.X
=
1233 Crosshair
.AttachedLine
.Point2
.X
;
1234 Crosshair
.AttachedLine
.Point1
.Y
=
1235 Crosshair
.AttachedLine
.Point2
.Y
;
1241 /* create line if both ends are determined && length != 0 */
1246 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && !TEST_SILK_LAYER (CURRENT
))
1247 line_flags
|= CONNECTEDFLAG
| FOUNDFLAG
;
1249 if (TEST_FLAG (CLEARNEWFLAG
, PCB
))
1250 line_flags
|= CLEARLINEFLAG
;
1253 && Crosshair
.AttachedLine
.Point1
.X
==
1254 Crosshair
.AttachedLine
.Point2
.X
1255 && Crosshair
.AttachedLine
.Point1
.Y
==
1256 Crosshair
.AttachedLine
.Point2
.Y
1257 && (Crosshair
.AttachedLine
.Point2
.X
!= Note
.X
1258 || Crosshair
.AttachedLine
.Point2
.Y
!= Note
.Y
))
1260 /* We will only need to paint the second line segment.
1261 Since we only check for vias on the first segment,
1262 swap them so the non-empty segment is the first segment. */
1263 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1264 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1267 if ((Crosshair
.AttachedLine
.Point1
.X
!=
1268 Crosshair
.AttachedLine
.Point2
.X
1269 || Crosshair
.AttachedLine
.Point1
.Y
!=
1270 Crosshair
.AttachedLine
.Point2
.Y
))
1275 CreateDrawnLineOnLayer (CURRENT
,
1276 Crosshair
.AttachedLine
.Point1
.X
,
1277 Crosshair
.AttachedLine
.Point1
.Y
,
1278 Crosshair
.AttachedLine
.Point2
.X
,
1279 Crosshair
.AttachedLine
.Point2
.Y
,
1280 Settings
.LineThickness
,
1281 2 * Settings
.Keepaway
,
1282 MakeFlags (line_flags
))) != NULL
)
1286 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1287 DrawLine (CURRENT
, line
);
1289 /* place a via if vias are visible, the layer is
1290 in a new group since the last line and there
1291 isn't a pin already here */
1292 if (PCB
->ViaOn
&& GetLayerGroupNumberByPointer (CURRENT
) !=
1293 GetLayerGroupNumberByPointer (lastLayer
) &&
1294 SearchObjectByLocation (PIN_TYPES
, &ptr1
, &ptr2
, &ptr3
,
1295 Crosshair
.AttachedLine
.Point1
.X
,
1296 Crosshair
.AttachedLine
.Point1
.Y
,
1297 Settings
.ViaThickness
/ 2) ==
1300 CreateNewVia (PCB
->Data
,
1301 Crosshair
.AttachedLine
.Point1
.X
,
1302 Crosshair
.AttachedLine
.Point1
.Y
,
1303 Settings
.ViaThickness
,
1304 2 * Settings
.Keepaway
, 0,
1305 Settings
.ViaDrillingHole
, NULL
,
1306 NoFlags ())) != NULL
)
1308 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1311 /* copy the coordinates */
1312 Crosshair
.AttachedLine
.Point1
.X
=
1313 Crosshair
.AttachedLine
.Point2
.X
;
1314 Crosshair
.AttachedLine
.Point1
.Y
=
1315 Crosshair
.AttachedLine
.Point2
.Y
;
1316 IncrementUndoSerialNumber ();
1317 lastLayer
= CURRENT
;
1319 if (PCB
->Clipping
&& (Note
.X
!= Crosshair
.AttachedLine
.Point2
.X
1321 Crosshair
.AttachedLine
.Point2
.Y
))
1324 CreateDrawnLineOnLayer (CURRENT
,
1325 Crosshair
.AttachedLine
.Point2
.X
,
1326 Crosshair
.AttachedLine
.Point2
.Y
,
1328 Settings
.LineThickness
,
1329 2 * Settings
.Keepaway
,
1330 MakeFlags (line_flags
))) != NULL
)
1333 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1334 IncrementUndoSerialNumber ();
1335 DrawLine (CURRENT
, line
);
1337 /* move to new start point */
1338 Crosshair
.AttachedLine
.Point1
.X
= Note
.X
;
1339 Crosshair
.AttachedLine
.Point1
.Y
= Note
.Y
;
1340 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1341 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1342 if (TEST_FLAG (SWAPSTARTDIRFLAG
, PCB
))
1347 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && !TEST_SILK_LAYER (CURRENT
))
1348 LookupConnection (Note
.X
, Note
.Y
, true, 1, CONNECTEDFLAG
, false);
1353 case RECTANGLE_MODE
:
1354 /* do update of position */
1357 /* create rectangle if both corners are determined
1358 * and width, height are != 0
1360 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
1361 Crosshair
.AttachedBox
.Point1
.X
!= Crosshair
.AttachedBox
.Point2
.X
&&
1362 Crosshair
.AttachedBox
.Point1
.Y
!= Crosshair
.AttachedBox
.Point2
.Y
)
1364 PolygonType
*polygon
;
1366 int flags
= CLEARPOLYFLAG
;
1367 if (TEST_FLAG (NEWFULLPOLYFLAG
, PCB
))
1368 flags
|= FULLPOLYFLAG
;
1369 if ((polygon
= CreateNewPolygonFromRectangle (CURRENT
,
1371 AttachedBox
.Point1
.X
,
1373 AttachedBox
.Point1
.Y
,
1375 AttachedBox
.Point2
.X
,
1377 AttachedBox
.Point2
.Y
,
1382 AddObjectToCreateUndoList (POLYGON_TYPE
, CURRENT
,
1384 IncrementUndoSerialNumber ();
1385 DrawPolygon (CURRENT
, polygon
);
1389 /* reset state to 'first corner' */
1390 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
1398 if ((string
= gui
->prompt_for (_("Enter text:"), "")) != NULL
)
1400 if (strlen(string
) > 0)
1403 int flag
= CLEARLINEFLAG
;
1405 if (GetLayerGroupNumberByNumber (INDEXOFCURRENT
) ==
1406 GetLayerGroupNumberBySide (BOTTOM_SIDE
))
1407 flag
|= ONSOLDERFLAG
;
1408 if ((text
= CreateNewText (CURRENT
, &PCB
->Font
, Note
.X
,
1409 Note
.Y
, 0, Settings
.TextScale
,
1410 string
, MakeFlags (flag
))) != NULL
)
1412 AddObjectToCreateUndoList (TEXT_TYPE
, CURRENT
, text
, text
);
1413 IncrementUndoSerialNumber ();
1414 DrawText (CURRENT
, text
);
1425 PointType
*points
= Crosshair
.AttachedPolygon
.Points
;
1426 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1428 /* do update of position; use the 'LINE_MODE' mechanism */
1431 /* check if this is the last point of a polygon */
1433 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1434 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1436 CopyAttachedPolygonToLayer ();
1441 /* create new point if it's the first one or if it's
1442 * different to the last one
1445 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1446 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1448 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1449 Crosshair
.AttachedLine
.Point2
.X
,
1450 Crosshair
.AttachedLine
.Point2
.Y
);
1452 /* copy the coordinates */
1453 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1454 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1459 case POLYGONHOLE_MODE
:
1461 switch (Crosshair
.AttachedObject
.State
)
1463 /* first notify, lookup object */
1465 Crosshair
.AttachedObject
.Type
=
1466 SearchScreen (Note
.X
, Note
.Y
, POLYGON_TYPE
,
1467 &Crosshair
.AttachedObject
.Ptr1
,
1468 &Crosshair
.AttachedObject
.Ptr2
,
1469 &Crosshair
.AttachedObject
.Ptr3
);
1471 if (Crosshair
.AttachedObject
.Type
== NO_TYPE
)
1473 Message (_("The first point of a polygon hole must be on a polygon.\n"));
1474 break; /* don't start doing anything if clicked outside of polys */
1477 if (TEST_FLAG(LOCKFLAG
, (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
))
1479 Message (_("Sorry, the object is locked\n"));
1480 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1484 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1485 /* Fall thru: first click is also the first point of the
1488 /* second notify, insert new point into object */
1491 PointType
*points
= Crosshair
.AttachedPolygon
.Points
;
1492 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1493 POLYAREA
*original
, *new_hole
, *result
;
1496 /* do update of position; use the 'LINE_MODE' mechanism */
1499 /* check if this is the last point of a polygon */
1501 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1502 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1504 /* Create POLYAREAs from the original polygon
1505 * and the new hole polygon */
1506 original
= PolygonToPoly ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
);
1507 new_hole
= PolygonToPoly (&Crosshair
.AttachedPolygon
);
1509 /* Subtract the hole from the original polygon shape */
1510 poly_Boolean_free (original
, new_hole
, &result
, PBO_SUB
);
1512 /* Convert the resulting polygon(s) into a new set of nodes
1513 * and place them on the page. Delete the original polygon.
1515 SaveUndoSerialNumber ();
1516 Flags
= ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
)->Flags
;
1517 PolyToPolygonsOnLayer (PCB
->Data
, (LayerType
*)Crosshair
.AttachedObject
.Ptr1
,
1519 RemoveObject (POLYGON_TYPE
,
1520 Crosshair
.AttachedObject
.Ptr1
,
1521 Crosshair
.AttachedObject
.Ptr2
,
1522 Crosshair
.AttachedObject
.Ptr3
);
1523 RestoreUndoSerialNumber ();
1524 IncrementUndoSerialNumber ();
1527 /* reset state of attached line */
1528 memset (&Crosshair
.AttachedPolygon
, 0, sizeof (PolygonType
));
1529 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1535 /* create new point if it's the first one or if it's
1536 * different to the last one
1539 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1540 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1542 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1543 Crosshair
.AttachedLine
.Point2
.X
,
1544 Crosshair
.AttachedLine
.Point2
.Y
);
1546 /* copy the coordinates */
1547 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1548 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1557 case PASTEBUFFER_MODE
:
1559 TextType estr
[MAX_ELEMENTNAMES
];
1562 if (gui
->shift_is_pressed ())
1565 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1567 if (type
== ELEMENT_TYPE
)
1569 e
= (ElementType
*) ptr1
;
1574 memcpy (estr
, e
->Name
,
1575 MAX_ELEMENTNAMES
* sizeof (TextType
));
1576 for (i
= 0; i
< MAX_ELEMENTNAMES
; ++i
)
1577 estr
[i
].TextString
= estr
[i
].TextString
? strdup(estr
[i
].TextString
) : NULL
;
1582 if (CopyPastebufferToLayout (Note
.X
, Note
.Y
))
1583 SetChangedFlag (true);
1587 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1589 if (type
== ELEMENT_TYPE
&& ptr1
)
1592 e
= (ElementType
*) ptr1
;
1594 save_n
= NAME_INDEX (PCB
);
1596 for (i
= 0; i
< MAX_ELEMENTNAMES
; i
++)
1599 EraseElementName (e
);
1600 r_delete_entry (PCB
->Data
->name_tree
[i
],
1601 (BoxType
*) & (e
->Name
[i
]));
1602 memcpy (&(e
->Name
[i
]), &(estr
[i
]), sizeof (TextType
));
1603 e
->Name
[i
].Element
= e
;
1604 SetTextBoundingBox (&PCB
->Font
, &(e
->Name
[i
]));
1605 r_insert_entry (PCB
->Data
->name_tree
[i
],
1606 (BoxType
*) & (e
->Name
[i
]), 0);
1608 DrawElementName (e
);
1617 SearchScreen (Note
.X
, Note
.Y
, REMOVE_TYPES
, &ptr1
, &ptr2
,
1620 if (TEST_FLAG (LOCKFLAG
, (LineType
*) ptr2
))
1622 Message (_("Sorry, the object is locked\n"));
1625 if (type
== ELEMENT_TYPE
)
1627 RubberbandType
*ptr
;
1630 Crosshair
.AttachedObject
.RubberbandN
= 0;
1631 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
1632 ptr
= Crosshair
.AttachedObject
.Rubberband
;
1633 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
; i
++)
1636 EraseRat ((RatType
*) ptr
->Line
);
1637 if (TEST_FLAG (RUBBERENDFLAG
, ptr
->Line
))
1638 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
1639 ptr
->Line
, ptr
->Line
,
1642 TOGGLE_FLAG (RUBBERENDFLAG
, ptr
->Line
); /* only remove line once */
1646 RemoveObject (type
, ptr1
, ptr2
, ptr3
);
1647 IncrementUndoSerialNumber ();
1648 SetChangedFlag (true);
1653 RotateScreenObject (Note
.X
, Note
.Y
,
1654 gui
->shift_is_pressed ()? (SWAP_IDENT
?
1656 : (SWAP_IDENT
? 3 : 1));
1659 /* both are almost the same */
1662 switch (Crosshair
.AttachedObject
.State
)
1664 /* first notify, lookup object */
1667 int types
= (Settings
.Mode
== COPY_MODE
) ?
1668 COPY_TYPES
: MOVE_TYPES
;
1670 Crosshair
.AttachedObject
.Type
=
1671 SearchScreen (Note
.X
, Note
.Y
, types
,
1672 &Crosshair
.AttachedObject
.Ptr1
,
1673 &Crosshair
.AttachedObject
.Ptr2
,
1674 &Crosshair
.AttachedObject
.Ptr3
);
1675 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1677 if (Settings
.Mode
== MOVE_MODE
&&
1678 TEST_FLAG (LOCKFLAG
, (PinType
*)
1679 Crosshair
.AttachedObject
.Ptr2
))
1681 Message (_("Sorry, the object is locked\n"));
1682 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1685 AttachForCopy (Note
.X
, Note
.Y
);
1690 /* second notify, move or copy object */
1692 if (Settings
.Mode
== COPY_MODE
)
1693 CopyObject (Crosshair
.AttachedObject
.Type
,
1694 Crosshair
.AttachedObject
.Ptr1
,
1695 Crosshair
.AttachedObject
.Ptr2
,
1696 Crosshair
.AttachedObject
.Ptr3
,
1697 Note
.X
- Crosshair
.AttachedObject
.X
,
1698 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1701 MoveObjectAndRubberband (Crosshair
.AttachedObject
.Type
,
1702 Crosshair
.AttachedObject
.Ptr1
,
1703 Crosshair
.AttachedObject
.Ptr2
,
1704 Crosshair
.AttachedObject
.Ptr3
,
1705 Note
.X
- Crosshair
.AttachedObject
.X
,
1706 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1707 SetLocalRef (0, 0, false);
1709 SetChangedFlag (true);
1711 /* reset identifiers */
1712 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1713 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1718 /* insert a point into a polygon/line/... */
1719 case INSERTPOINT_MODE
:
1720 switch (Crosshair
.AttachedObject
.State
)
1722 /* first notify, lookup object */
1724 Crosshair
.AttachedObject
.Type
=
1725 SearchScreen (Note
.X
, Note
.Y
, INSERT_TYPES
,
1726 &Crosshair
.AttachedObject
.Ptr1
,
1727 &Crosshair
.AttachedObject
.Ptr2
,
1728 &Crosshair
.AttachedObject
.Ptr3
);
1730 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1732 if (TEST_FLAG (LOCKFLAG
, (PolygonType
*)
1733 Crosshair
.AttachedObject
.Ptr2
))
1735 Message (_("Sorry, the object is locked\n"));
1736 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1741 /* get starting point of nearest segment */
1742 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1745 (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
;
1747 GetLowestDistancePolygonPoint (fake
.poly
, Note
.X
,
1749 fake
.line
.Point1
= fake
.poly
->Points
[polyIndex
];
1750 fake
.line
.Point2
= fake
.poly
->Points
[
1751 prev_contour_point (fake
.poly
, polyIndex
)];
1752 Crosshair
.AttachedObject
.Ptr2
= &fake
.line
;
1755 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1756 InsertedPoint
= *AdjustInsertPoint ();
1761 /* second notify, insert new point into object */
1763 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1764 InsertPointIntoObject (POLYGON_TYPE
,
1765 Crosshair
.AttachedObject
.Ptr1
, fake
.poly
,
1767 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1769 InsertPointIntoObject (Crosshair
.AttachedObject
.Type
,
1770 Crosshair
.AttachedObject
.Ptr1
,
1771 Crosshair
.AttachedObject
.Ptr2
,
1773 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1774 SetChangedFlag (true);
1776 /* reset identifiers */
1777 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1778 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1786 /* --------------------------------------------------------------------------- */
1788 static const char atomic_syntax
[] = N_("Atomic(Save|Restore|Close|Block)");
1790 static const char atomic_help
[] = N_("Save or restore the undo serial number.");
1792 /* %start-doc actions Atomic
1794 This action allows making multiple-action bindings into an atomic
1795 operation that will be undone by a single Undo command. For example,
1796 to optimize rat lines, you'd delete the rats and re-add them. To
1797 group these into a single undo, you'd want the deletions and the
1798 additions to have the same undo serial number. So, you @code{Save},
1799 delete the rats, @code{Restore}, add the rats - using the same serial
1800 number as the deletes, then @code{Block}, which checks to see if the
1801 deletions or additions actually did anything. If not, the serial
1802 number is set to the saved number, as there's nothing to undo. If
1803 something did happen, the serial number is incremented so that these
1804 actions are counted as a single undo step.
1809 Saves the undo serial number.
1812 Returns it to the last saved number.
1815 Sets it to 1 greater than the last save.
1818 Does a Restore if there was nothing to undo, else does a Close.
1825 ActionAtomic (int argc
, char **argv
, Coord x
, Coord y
)
1830 switch (GetFunctionID (argv
[0]))
1833 SaveUndoSerialNumber ();
1836 RestoreUndoSerialNumber ();
1839 RestoreUndoSerialNumber ();
1840 IncrementUndoSerialNumber ();
1843 RestoreUndoSerialNumber ();
1845 IncrementUndoSerialNumber ();
1851 /* -------------------------------------------------------------------------- */
1853 static const char drc_syntax
[] = N_("DRC()");
1855 static const char drc_help
[] = N_("Invoke the DRC check.");
1857 /* %start-doc actions DRC
1859 Note that the design rule check uses the current board rule settings,
1860 not the current style settings.
1865 ActionDRCheck (int argc
, char **argv
, Coord x
, Coord y
)
1869 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1871 Message (_("%m+Rules are minspace %$mS, minoverlap %$mS "
1872 "minwidth %$mS, minsilk %$mS\n"
1873 "min drill %$mS, min annular ring %$mS\n"),
1874 Settings
.grid_unit
->allow
,
1875 PCB
->Bloat
, PCB
->Shrink
,
1876 PCB
->minWid
, PCB
->minSlk
,
1877 PCB
->minDrill
, PCB
->minRing
);
1880 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1883 Message (_("No DRC problems found.\n"));
1885 Message (_("Found %d design rule errors.\n"), count
);
1887 Message (_("Aborted DRC after %d design rule errors.\n"), -count
);
1892 /* -------------------------------------------------------------------------- */
1894 static const char dumplibrary_syntax
[] = N_("DumpLibrary()");
1896 static const char dumplibrary_help
[] =
1897 N_("Display the entire contents of the libraries.");
1899 /* %start-doc actions DumpLibrary
1905 ActionDumpLibrary (int argc
, char **argv
, Coord x
, Coord y
)
1909 printf ("**** Do not count on this format. It will change ****\n\n");
1910 printf ("MenuN = %d\n", (int) Library
.MenuN
);
1911 printf ("MenuMax = %d\n", (int) Library
.MenuMax
);
1912 for (i
= 0; i
< Library
.MenuN
; i
++)
1914 printf ("Library #%d:\n", i
);
1915 printf (" EntryN = %d\n", (int) Library
.Menu
[i
].EntryN
);
1916 printf (" EntryMax = %d\n", (int) Library
.Menu
[i
].EntryMax
);
1917 printf (" Name = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Name
));
1918 printf (" directory = \"%s\"\n",
1919 UNKNOWN (Library
.Menu
[i
].directory
));
1920 printf (" Style = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Style
));
1921 printf (" flag = %d\n", Library
.Menu
[i
].flag
);
1923 for (j
= 0; j
< Library
.Menu
[i
].EntryN
; j
++)
1925 printf (" #%4d: ", j
);
1926 if (Library
.Menu
[i
].Entry
[j
].Template
== (char *) -1)
1928 printf ("newlib: \"%s\"\n",
1929 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
));
1933 printf ("\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"\n",
1934 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
),
1935 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Template
),
1936 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Package
),
1937 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Value
),
1938 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Description
));
1946 /* -------------------------------------------------------------------------- */
1948 static const char flip_syntax
[] = N_("Flip(Object|Selected|SelectedElements)");
1950 static const char flip_help
[] =
1951 N_("Flip an element to the opposite side of the board.");
1953 /* %start-doc actions Flip
1955 Note that the location of the element will be symmetric about the
1956 cursor location; i.e. if the part you are pointing at will still be at
1957 the same spot once the element is on the other side. When flipping
1958 multiple elements, this retains their positions relative to each
1959 other, not their absolute positions on the board.
1964 ActionFlip (int argc
, char **argv
, Coord x
, Coord y
)
1966 char *function
= ARG (0);
1967 ElementType
*element
;
1973 switch (GetFunctionID (function
))
1976 if ((SearchScreen (x
, y
, ELEMENT_TYPE
,
1977 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
1979 element
= (ElementType
*) ptrtmp
;
1980 ChangeElementSide (element
, 2 * Crosshair
.Y
- PCB
->MaxHeight
);
1981 IncrementUndoSerialNumber ();
1986 case F_SelectedElements
:
1987 ChangeSelectedElementSide ();
2000 /* -------------------------------------------------------------------------- */
2002 static const char message_syntax
[] = N_("Message(message)");
2004 static const char message_help
[] = N_("Writes a message to the log window.");
2006 /* %start-doc actions Message
2008 This action displays a message to the log window. This action is primarily
2009 provided for use by other programs which may interface with PCB. If
2010 multiple arguments are given, each one is sent to the log window
2011 followed by a newline.
2016 ActionMessage (int argc
, char **argv
, Coord x
, Coord y
)
2023 for (i
= 0; i
< argc
; i
++)
2033 /* -------------------------------------------------------------------------- */
2035 static const char setthermal_syntax
[] =
2036 "SetThermal(Object|SelectedPins|SelectedVias|Selected, Style)";
2038 static const char setthermal_help
[] =
2039 N_("Set the thermal (on the current layer) of pins or vias to the given style.\n"
2040 "Style = 0 means no thermal.\n"
2041 "Style = 1 has diagonal fingers with sharp edges.\n"
2042 "Style = 2 has horizontal and vertical fingers with sharp edges.\n"
2043 "Style = 3 is a solid connection to the plane.\n"
2044 "Style = 4 has diagonal fingers with rounded edges.\n"
2045 "Style = 5 has horizontal and vertical fingers with rounded edges.\n");
2047 /* %start-doc actions SetThermal
2049 This changes how/whether pins or vias connect to any rectangle or polygon
2050 on the current layer. The first argument can specify one object, or all
2051 selected pins, or all selected vias, or all selected pins and vias.
2052 The second argument specifies the style of connection.
2053 There are 5 possibilities:
2055 1 - 45 degree fingers with sharp edges,
2056 2 - horizontal & vertical fingers with sharp edges,
2057 3 - solid connection,
2058 4 - 45 degree fingers with rounded corners,
2059 5 - horizontal & vertical fingers with rounded corners.
2061 Pins and Vias may have thermals whether or not there is a polygon available
2062 to connect with. However, they will have no effect without the polygon.
2066 ActionSetThermal (int argc
, char **argv
, Coord x
, Coord y
)
2068 char *function
= ARG (0);
2069 char *style
= ARG (1);
2070 void *ptr1
, *ptr2
, *ptr3
;
2074 if (function
&& *function
)
2078 if ( ! style
|| ! *style
)
2080 kind
= PCB
->ThermStyle
;
2084 kind
= GetUnitlessValue (style
, &absolute
);
2086 /* To allow relative values we could search for the first selected
2087 item and make 'kind' relative to that, but that's not too useful
2088 and requires quite some code. For example there's no
2089 GetFirstSelectedPin() function available. Let's postpone this
2090 functionality, there are more urgent things to do. */
2093 switch (GetFunctionID (function
))
2097 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGETHERMAL_TYPES
,
2098 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
2100 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, kind
);
2101 IncrementUndoSerialNumber ();
2105 case F_SelectedPins
:
2106 ChangeSelectedThermals (PIN_TYPE
, kind
);
2108 case F_SelectedVias
:
2109 ChangeSelectedThermals (VIA_TYPE
, kind
);
2112 case F_SelectedElements
:
2113 ChangeSelectedThermals (CHANGETHERMAL_TYPES
, kind
);
2132 * \brief Event handler to set the cursor according to the X pointer
2133 * position called from inside main.c.
2135 * \warning !!! no action routine !!!
2138 EventMoveCrosshair (int ev_x
, int ev_y
)
2140 #ifdef HAVE_LIBSTROKE
2143 StrokeBox
.X2
= ev_x
;
2144 StrokeBox
.Y2
= ev_y
;
2145 stroke_record (ev_x
, ev_y
);
2148 #endif /* HAVE_LIBSTROKE */
2149 if (MoveCrosshairAbsolute (ev_x
, ev_y
))
2151 /* update object position and cursor location */
2152 AdjustAttachedObjects ();
2153 notify_crosshair_change (true);
2157 /* --------------------------------------------------------------------------- */
2159 static const char setvalue_syntax
[] =
2160 N_("SetValue(Grid|Line|LineSize|Text|TextScale|ViaDrillingHole|Via|ViaSize, "
2163 static const char setvalue_help
[] =
2164 N_("Change various board-wide values and sizes.");
2166 /* %start-doc actions SetValue
2170 @item ViaDrillingHole
2171 Changes the diameter of the drill for new vias.
2174 Sets the grid spacing.
2178 Changes the thickness of new lines.
2182 Changes the diameter of new vias.
2186 Changes the size of new text.
2193 ActionSetValue (int argc
, char **argv
, Coord x
, Coord y
)
2195 char *function
= ARG (0);
2196 char *val
= ARG (1);
2197 char *units
= ARG (2);
2198 bool absolute
; /* flag for 'absolute' value */
2203 if (function
&& val
)
2205 value
= GetValue (val
, units
, &absolute
);
2206 switch (GetFunctionID (function
))
2208 case F_ViaDrillingHole
:
2209 SetViaDrillingHole (absolute
? value
:
2210 value
+ Settings
.ViaDrillingHole
,
2212 hid_action ("RouteStylesChanged");
2217 SetGrid (value
, false);
2221 value
= val
[0] == '-' ? -Settings
.increments
->grid
2222 : Settings
.increments
->grid
;
2223 /* On the way down, short against the minimum
2224 * PCB drawing unit */
2225 if ((value
+ PCB
->Grid
) < 1)
2227 else if (PCB
->Grid
== 1)
2228 SetGrid (value
, false);
2230 SetGrid (value
+ PCB
->Grid
, false);
2236 if (!absolute
&& value
== 0)
2237 value
= val
[0] == '-' ? -Settings
.increments
->line
2238 : Settings
.increments
->line
;
2239 SetLineSize (absolute
? value
: value
+ Settings
.LineThickness
);
2240 hid_action ("RouteStylesChanged");
2245 SetViaSize (absolute
? value
: value
+ Settings
.ViaThickness
, false);
2246 hid_action ("RouteStylesChanged");
2251 text_scale
= value
/ (double)FONT_CAPHEIGHT
* 100.;
2253 text_scale
+= Settings
.TextScale
;
2254 SetTextScale (text_scale
);
2268 /* --------------------------------------------------------------------------- */
2270 static const char quit_syntax
[] = N_("Quit()");
2272 static const char quit_help
[] = N_("Quits the application after confirming.");
2274 /* %start-doc actions Quit
2276 If you have unsaved changes, you will be prompted to confirm (or
2277 save) before quitting.
2282 ActionQuit (int argc
, char **argv
, Coord x
, Coord y
)
2284 char *force
= ARG (0);
2285 if (force
&& strcasecmp (force
, "force") == 0)
2290 if (!PCB
->Changed
|| gui
->close_confirm_dialog () == HID_CLOSE_CONFIRM_OK
)
2295 /* --------------------------------------------------------------------------- */
2297 static const char connection_syntax
[] =
2298 N_("Connection(Find|ResetLinesAndPolygons|ResetPinsAndVias|Reset)");
2300 static const char connection_help
[] =
2301 N_("Searches connections of the object at the cursor position.");
2303 /* %start-doc actions Connection
2305 Connections found with this action will be highlighted in the
2306 ``connected-color'' color and will have the ``found'' flag set.
2311 The net under the cursor is ``found''.
2313 @item ResetLinesAndPolygons
2314 Any ``found'' lines and polygons are marked ``not found''.
2316 @item ResetPinsAndVias
2317 Any ``found'' pins and vias are marked ``not found''.
2320 All ``found'' objects are marked ``not found''.
2327 ActionConnection (int argc
, char **argv
, Coord x
, Coord y
)
2329 char *function
= ARG (0);
2332 switch (GetFunctionID (function
))
2336 gui
->get_coords (_("Click on a connection"), &x
, &y
);
2337 LookupConnection (x
, y
, true, 1, CONNECTEDFLAG
, false);
2338 LookupConnection (x
, y
, true, 1, FOUNDFLAG
, true);
2342 case F_ResetLinesAndPolygons
:
2343 if (ClearFlagOnLinesAndPolygons (true, CONNECTEDFLAG
| FOUNDFLAG
))
2345 IncrementUndoSerialNumber ();
2350 case F_ResetPinsViasAndPads
:
2351 if (ClearFlagOnPinsViasAndPads (true, CONNECTEDFLAG
| FOUNDFLAG
))
2353 IncrementUndoSerialNumber ();
2359 if (ClearFlagOnAllObjects (true, CONNECTEDFLAG
| FOUNDFLAG
))
2361 IncrementUndoSerialNumber ();
2372 /* --------------------------------------------------------------------------- */
2374 static const char disperseelements_syntax
[] =
2375 N_("DisperseElements(All|Selected)");
2377 static const char disperseelements_help
[] = N_("Disperses elements.");
2379 /* %start-doc actions DisperseElements
2381 Normally this is used when starting a board, by selecting all elements
2382 and then dispersing them. This scatters the elements around the board
2383 so that you can pick individual ones, rather than have all the
2384 elements at the same 0,0 coordinate and thus impossible to choose
2389 #define GAP MIL_TO_COORD(100)
2392 ActionDisperseElements (int argc
, char **argv
, Coord x
, Coord y
)
2394 char *function
= ARG (0);
2399 int all
= 0, bad
= 0;
2401 if (!function
|| !*function
)
2407 switch (GetFunctionID (function
))
2424 AFAIL (disperseelements
);
2428 ELEMENT_LOOP (PCB
->Data
);
2431 * If we want to disperse selected elements, maybe we need smarter
2432 * code here to avoid putting components on top of others which
2433 * are not selected. For now, I'm assuming that this is typically
2434 * going to be used either with a brand new design or a scratch
2435 * design holding some new components
2437 if (!TEST_FLAG (LOCKFLAG
, element
) && (all
|| TEST_FLAG (SELECTEDFLAG
, element
)))
2440 /* figure out how much to move the element */
2441 dx
= minx
- element
->BoundingBox
.X1
;
2443 /* snap to the grid */
2444 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2447 * and add one grid size so we make sure we always space by GAP or
2452 /* Figure out if this row has room. If not, start a new row */
2453 if (GAP
+ element
->BoundingBox
.X2
+ dx
> PCB
->MaxWidth
)
2459 /* figure out how much to move the element */
2460 dx
= minx
- element
->BoundingBox
.X1
;
2461 dy
= miny
- element
->BoundingBox
.Y1
;
2463 /* snap to the grid */
2464 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2466 dy
-= (element
->MarkY
+ dy
) % PCB
->Grid
;
2469 /* move the element */
2470 MoveElementLowLevel (PCB
->Data
, element
, dx
, dy
);
2472 /* and add to the undo list so we can undo this operation */
2473 AddObjectToMoveUndoList (ELEMENT_TYPE
, NULL
, NULL
, element
, dx
, dy
);
2475 /* keep track of how tall this row is */
2476 minx
+= element
->BoundingBox
.X2
- element
->BoundingBox
.X1
+ GAP
;
2477 if (maxy
< element
->BoundingBox
.Y2
)
2479 maxy
= element
->BoundingBox
.Y2
;
2486 /* done with our action so increment the undo # */
2487 IncrementUndoSerialNumber ();
2490 SetChangedFlag (true);
2497 /* --------------------------------------------------------------------------- */
2499 static const char display_syntax
[] =
2500 N_("Display(NameOnPCB|Description|Value)\n"
2501 "Display(Grid|Redraw)\n"
2502 "Display(CycleClip|CycleCrosshair|Toggle45Degree|ToggleStartDirection)\n"
2503 "Display(ToggleGrid|ToggleRubberBandMode|ToggleUniqueNames)\n"
2504 "Display(ToggleMask|ToggleName|ToggleClearLine|ToggleFullPoly|ToggleSnapPin)\n"
2505 "Display(ToggleThindraw|ToggleThindrawPoly|ToggleOrthoMove|ToggleLocalRef)\n"
2506 "Display(ToggleCheckPlanes|ToggleShowDRC|ToggleAutoDRC)\n"
2507 "Display(ToggleLiveRoute|LockNames|OnlyNames)\n"
2508 "Display(Pinout|PinOrPadName)");
2510 static const char display_help
[] = N_("Several display-related actions.");
2512 /* %start-doc actions Display
2519 Specify whether all elements show their name, description, or value.
2522 Redraw the whole board.
2524 @item Toggle45Degree
2525 When clear, lines can be drawn at any angle. When set, lines are
2526 restricted to multiples of 45 degrees and requested lines may be
2527 broken up according to the clip setting.
2530 Changes the way lines are restricted to 45 degree increments. The
2531 various settings are: straight only, orthogonal then angled, and angled
2532 then orthogonal. If AllDirections is set, this action disables it.
2534 @item CycleCrosshair
2535 Changes crosshair drawing. Crosshair may accept form of 4-ray,
2536 8-ray and 12-ray cross.
2538 @item ToggleRubberBandMode
2539 If set, moving an object moves all the lines attached to it too.
2541 @item ToggleStartDirection
2542 If set, each time you set a point in a line, the Clip toggles between
2543 orth-angle and angle-ortho.
2545 @item ToggleUniqueNames
2546 If set, you will not be permitted to change the name of an element to
2547 match that of another element.
2550 If set, pin centers and pad end points are treated as additional grid
2551 points that the cursor can snap to.
2553 @item ToggleLocalRef
2554 If set, the mark is automatically set to the beginning of any move, so
2555 you can see the relative distance you've moved.
2557 @item ToggleThindraw
2558 If set, objects on the screen are drawn as outlines (lines are drawn
2559 as center-lines). This lets you see line endpoints hidden under pins,
2562 @item ToggleThindrawPoly
2563 If set, polygons on the screen are drawn as outlines.
2566 If set, pending objects (i.e. lines you're in the process of drawing)
2567 will be drawn with an outline showing how far away from other copper
2570 @item ToggleLiveRoute
2571 If set, the progress of the autorouter will be visible on the screen.
2574 If set, you will not be permitted to make connections which violate
2575 the current DRC and netlist settings.
2577 @item ToggleCheckPlanes
2578 If set, lines and arcs aren't drawn, which usually leaves just the
2579 polygons. If you also disable all but the layer you're interested in,
2580 this allows you to check for isolated regions.
2582 @item ToggleOrthoMove
2583 If set, the crosshair is only allowed to move orthogonally from its
2584 previous position. I.e. you can move an element or line up, down,
2585 left, or right, but not up+left or down+right.
2588 Selects whether the pinouts show the pin names or the pin numbers.
2590 @item ToggleLockNames
2591 If set, text will ignore left mouse clicks and actions that work on
2592 objects under the mouse. You can still select text with a lasso (left
2593 mouse drag) and perform actions on the selection.
2595 @item ToggleOnlyNames
2596 If set, only text will be sensitive for mouse clicks and actions that
2597 work on objects under the mouse. You can still select other objects
2598 with a lasso (left mouse drag) and perform actions on the selection.
2601 Turns the solder mask on or off.
2603 @item ToggleClearLine
2604 When set, the clear-line flag causes new lines and arcs to have their
2605 ``clear polygons'' flag set, so they won't be electrically connected
2606 to any polygons they overlap.
2608 @item ToggleFullPoly
2609 When set, the full-poly flag causes new polygons to have their
2610 ``full polygon'' flag set, so all parts of them will be displayed
2611 instead of only the biggest one.
2614 Resets the origin of the current grid to be wherever the mouse pointer
2615 is (not where the crosshair currently is). If you provide two numbers
2616 after this, the origin is set to that coordinate.
2619 Toggles whether the grid is displayed or not.
2622 Causes the pinout of the element indicated by the cursor to be
2623 displayed, usually in a separate window.
2626 Toggles whether the names of pins, pads, or (yes) vias will be
2627 displayed. If the cursor is over an element, all of its pins and pads
2634 static enum crosshair_shape
2635 CrosshairShapeIncrement (enum crosshair_shape shape
)
2639 case Basic_Crosshair_Shape
:
2640 shape
= Union_Jack_Crosshair_Shape
;
2642 case Union_Jack_Crosshair_Shape
:
2643 shape
= Dozen_Crosshair_Shape
;
2645 case Dozen_Crosshair_Shape
:
2646 shape
= Crosshair_Shapes_Number
;
2648 case Crosshair_Shapes_Number
:
2649 shape
= Basic_Crosshair_Shape
;
2656 ActionDisplay (int argc
, char **argv
, Coord childX
, Coord childY
)
2658 char *function
, *str_dir
;
2665 if (function
&& (!str_dir
|| !*str_dir
))
2667 switch (id
= GetFunctionID (function
))
2671 case F_ClearAndRedraw
:
2676 /* change the displayed name of elements */
2680 ELEMENT_LOOP (PCB
->Data
);
2682 EraseElementName (element
);
2685 CLEAR_FLAG (DESCRIPTIONFLAG
| NAMEONPCBFLAG
, PCB
);
2691 SET_FLAG (NAMEONPCBFLAG
, PCB
);
2694 SET_FLAG (DESCRIPTIONFLAG
, PCB
);
2697 ELEMENT_LOOP (PCB
->Data
);
2699 DrawElementName (element
);
2705 /* toggle line-adjust flag */
2706 case F_ToggleAllDirections
:
2707 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2708 AdjustAttachedObjects ();
2712 notify_crosshair_change (false);
2713 if (TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
2715 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2719 PCB
->Clipping
= (PCB
->Clipping
+ 1) % 3;
2720 AdjustAttachedObjects ();
2721 notify_crosshair_change (true);
2724 case F_CycleCrosshair
:
2725 notify_crosshair_change (false);
2726 Crosshair
.shape
= CrosshairShapeIncrement(Crosshair
.shape
);
2727 if (Crosshair_Shapes_Number
== Crosshair
.shape
)
2728 Crosshair
.shape
= Basic_Crosshair_Shape
;
2729 notify_crosshair_change (true);
2732 case F_ToggleRubberBandMode
:
2733 notify_crosshair_change (false);
2734 TOGGLE_FLAG (RUBBERBANDFLAG
, PCB
);
2735 notify_crosshair_change (true);
2738 case F_ToggleStartDirection
:
2739 notify_crosshair_change (false);
2740 TOGGLE_FLAG (SWAPSTARTDIRFLAG
, PCB
);
2741 notify_crosshair_change (true);
2744 case F_ToggleUniqueNames
:
2745 TOGGLE_FLAG (UNIQUENAMEFLAG
, PCB
);
2748 case F_ToggleSnapPin
:
2749 notify_crosshair_change (false);
2750 TOGGLE_FLAG (SNAPPINFLAG
, PCB
);
2751 notify_crosshair_change (true);
2754 case F_ToggleLocalRef
:
2755 TOGGLE_FLAG (LOCALREFFLAG
, PCB
);
2758 case F_ToggleThindraw
:
2759 TOGGLE_FLAG (THINDRAWFLAG
, PCB
);
2763 case F_ToggleThindrawPoly
:
2764 TOGGLE_FLAG (THINDRAWPOLYFLAG
, PCB
);
2768 case F_ToggleLockNames
:
2769 TOGGLE_FLAG (LOCKNAMESFLAG
, PCB
);
2770 CLEAR_FLAG (ONLYNAMESFLAG
, PCB
);
2773 case F_ToggleOnlyNames
:
2774 TOGGLE_FLAG (ONLYNAMESFLAG
, PCB
);
2775 CLEAR_FLAG (LOCKNAMESFLAG
, PCB
);
2778 case F_ToggleHideNames
:
2779 TOGGLE_FLAG (HIDENAMESFLAG
, PCB
);
2783 case F_ToggleShowDRC
:
2784 TOGGLE_FLAG (SHOWDRCFLAG
, PCB
);
2787 case F_ToggleLiveRoute
:
2788 TOGGLE_FLAG (LIVEROUTEFLAG
, PCB
);
2791 case F_ToggleAutoDRC
:
2792 notify_crosshair_change (false);
2793 TOGGLE_FLAG (AUTODRCFLAG
, PCB
);
2794 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
2796 if (ClearFlagOnAllObjects (true, CONNECTEDFLAG
| FOUNDFLAG
))
2798 IncrementUndoSerialNumber ();
2801 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
2803 LookupConnection (Crosshair
.AttachedLine
.Point1
.X
,
2804 Crosshair
.AttachedLine
.Point1
.Y
,
2805 true, 1, CONNECTEDFLAG
, false);
2806 LookupConnection (Crosshair
.AttachedLine
.Point1
.X
,
2807 Crosshair
.AttachedLine
.Point1
.Y
,
2808 true, 1, FOUNDFLAG
, true);
2811 notify_crosshair_change (true);
2814 case F_ToggleCheckPlanes
:
2815 TOGGLE_FLAG (CHECKPLANESFLAG
, PCB
);
2819 case F_ToggleOrthoMove
:
2820 TOGGLE_FLAG (ORTHOMOVEFLAG
, PCB
);
2824 TOGGLE_FLAG (SHOWNUMBERFLAG
, PCB
);
2829 TOGGLE_FLAG (SHOWMASKFLAG
, PCB
);
2833 case F_ToggleClearLine
:
2834 TOGGLE_FLAG (CLEARNEWFLAG
, PCB
);
2837 case F_ToggleFullPoly
:
2838 TOGGLE_FLAG (NEWFULLPOLYFLAG
, PCB
);
2841 /* shift grid alignment */
2844 Coord oldGrid
= PCB
->Grid
;
2847 if (MoveCrosshairAbsolute (Crosshair
.X
, Crosshair
.Y
))
2848 notify_crosshair_change (true); /* first notify was in MoveCrosshairAbs */
2849 SetGrid (oldGrid
, true);
2853 /* toggle displaying of the grid */
2855 Settings
.DrawGrid
= !Settings
.DrawGrid
;
2859 /* display the pinout of an element */
2862 ElementType
*element
;
2866 gui
->get_coords (_("Click on an element"), &x
, &y
);
2868 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
2869 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
2871 element
= (ElementType
*) ptrtmp
;
2872 gui
->show_item (element
);
2877 /* toggle displaying of pin/pad/via names */
2878 case F_PinOrPadName
:
2880 void *ptr1
, *ptr2
, *ptr3
;
2883 gui
->get_coords(_("Click on an element"), &x
, &y
);
2885 switch (SearchScreen (x
, y
,
2886 ELEMENT_TYPE
| PIN_TYPE
| PAD_TYPE
|
2887 VIA_TYPE
, (void **) &ptr1
, (void **) &ptr2
,
2891 PIN_LOOP ((ElementType
*) ptr1
);
2893 if (TEST_FLAG (DISPLAYNAMEFLAG
, pin
))
2897 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, pin
, pin
);
2898 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pin
);
2901 PAD_LOOP ((ElementType
*) ptr1
);
2903 if (TEST_FLAG (DISPLAYNAMEFLAG
, pad
))
2907 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, pad
, pad
);
2908 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pad
);
2911 SetChangedFlag (true);
2912 IncrementUndoSerialNumber ();
2917 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
))
2918 ErasePinName ((PinType
*) ptr2
);
2920 DrawPinName ((PinType
*) ptr2
);
2921 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, ptr2
, ptr3
);
2922 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
);
2923 SetChangedFlag (true);
2924 IncrementUndoSerialNumber ();
2929 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PadType
*) ptr2
))
2930 ErasePadName ((PadType
*) ptr2
);
2932 DrawPadName ((PadType
*) ptr2
);
2933 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, ptr2
, ptr3
);
2934 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PadType
*) ptr2
);
2935 SetChangedFlag (true);
2936 IncrementUndoSerialNumber ();
2940 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
))
2941 EraseViaName ((PinType
*) ptr2
);
2943 DrawViaName ((PinType
*) ptr2
);
2944 AddObjectToFlagUndoList (VIA_TYPE
, ptr1
, ptr2
, ptr3
);
2945 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
);
2946 SetChangedFlag (true);
2947 IncrementUndoSerialNumber ();
2957 else if (function
&& str_dir
)
2959 switch (GetFunctionID (function
))
2964 PCB
->GridOffsetX
= GetValue (argv
[1], NULL
, NULL
);
2965 PCB
->GridOffsetY
= GetValue (argv
[2], NULL
, NULL
);
2966 if (Settings
.DrawGrid
)
2985 /* --------------------------------------------------------------------------- */
2987 static const char mode_syntax
[] =
2988 N_("Mode(Arc|Arrow|Copy|InsertPoint|Line|Lock|Move|None|PasteBuffer)\n"
2989 "Mode(Polygon|Rectangle|Remove|Rotate|Text|Thermal|Via)\n"
2990 "Mode(Notify|Release|Cancel|Stroke)\n"
2991 "Mode(Save|Restore)");
2993 static const char mode_help
[] = N_("Change or use the tool mode.");
2995 /* %start-doc actions Mode
3015 Select the indicated tool.
3018 Called when you press the mouse button, or move the mouse.
3021 Called when you release the mouse button.
3024 Cancels any pending tool activity, allowing you to restart elsewhere.
3025 For example, this allows you to start a new line rather than attach a
3026 line to the previous line.
3029 Similar to Cancel but calling this action a second time will return
3033 If your @code{pcb} was built with libstroke, this invokes the stroke
3034 input method. If not, this will restart a drawing mode if you were
3035 drawing, else it will select objects.
3038 Remembers the current tool.
3041 Restores the tool to the last saved tool.
3048 ActionMode (int argc
, char **argv
, Coord x
, Coord y
)
3050 char *function
= ARG (0);
3054 Note
.X
= Crosshair
.X
;
3055 Note
.Y
= Crosshair
.Y
;
3056 notify_crosshair_change (false);
3057 switch (GetFunctionID (function
))
3063 SetMode (ARROW_MODE
);
3066 SetMode (COPY_MODE
);
3069 SetMode (INSERTPOINT_MODE
);
3072 SetMode (LINE_MODE
);
3075 SetMode (LOCK_MODE
);
3078 SetMode (MOVE_MODE
);
3085 int saved_mode
= Settings
.Mode
;
3087 SetMode (saved_mode
);
3092 switch (Settings
.Mode
)
3095 case PASTEBUFFER_MODE
:
3101 case INSERTPOINT_MODE
:
3102 case RUBBERBANDMOVE_MODE
:
3106 SetMode (ARROW_MODE
);
3110 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3111 SetMode (ARROW_MODE
);
3115 SetMode (LINE_MODE
);
3119 case RECTANGLE_MODE
:
3120 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3121 SetMode (ARROW_MODE
);
3125 SetMode (RECTANGLE_MODE
);
3130 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3131 SetMode (ARROW_MODE
);
3135 SetMode (POLYGON_MODE
);
3139 case POLYGONHOLE_MODE
:
3140 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3141 SetMode (ARROW_MODE
);
3145 SetMode (POLYGONHOLE_MODE
);
3150 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3151 SetMode (ARROW_MODE
);
3172 SetMode (PASTEBUFFER_MODE
);
3175 SetMode (POLYGON_MODE
);
3178 SetMode (POLYGONHOLE_MODE
);
3180 #ifndef HAVE_LIBSTROKE
3193 SetMode (REMOVE_MODE
);
3196 SetMode (RECTANGLE_MODE
);
3199 SetMode (ROTATE_MODE
);
3202 #ifdef HAVE_LIBSTROKE
3204 StrokeBox
.X1
= Crosshair
.X
;
3205 StrokeBox
.Y1
= Crosshair
.Y
;
3208 /* Handle middle mouse button restarts of drawing mode. If not in
3209 | a drawing mode, middle mouse button will select objects.
3211 if (Settings
.Mode
== LINE_MODE
3212 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3214 SetMode (LINE_MODE
);
3216 else if (Settings
.Mode
== ARC_MODE
3217 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3219 else if (Settings
.Mode
== RECTANGLE_MODE
3220 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3221 SetMode (RECTANGLE_MODE
);
3222 else if (Settings
.Mode
== POLYGON_MODE
3223 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3224 SetMode (POLYGON_MODE
);
3229 SetMode (ARROW_MODE
);
3235 SetMode (TEXT_MODE
);
3238 SetMode (THERMAL_MODE
);
3244 case F_Restore
: /* restore the last saved mode */
3248 case F_Save
: /* save currently selected mode */
3252 notify_crosshair_change (true);
3259 /* --------------------------------------------------------------------------- */
3261 static const char removeselected_syntax
[] = N_("RemoveSelected()");
3263 static const char removeselected_help
[] = N_("Removes any selected objects.");
3265 /* %start-doc actions RemoveSelected
3270 ActionRemoveSelected (int argc
, char **argv
, Coord x
, Coord y
)
3272 if (RemoveSelected ())
3273 SetChangedFlag (true);
3277 /* --------------------------------------------------------------------------- */
3279 static const char renumber_syntax
[] = N_("Renumber()\n"
3280 "Renumber(filename)");
3282 static const char renumber_help
[] =
3283 N_("Renumber all elements. The changes will be recorded to filename\n"
3284 "for use in backannotating these changes to the schematic.");
3286 /* %start-doc actions Renumber
3291 ActionRenumber (int argc
, char **argv
, Coord x
, Coord y
)
3293 bool changed
= false;
3294 ElementType
**element_list
;
3295 ElementType
**locked_element_list
;
3296 unsigned int i
, j
, k
, cnt
, lock_cnt
;
3302 static char * default_file
= NULL
;
3303 size_t cnt_list_sz
= 100;
3309 char **was
, **is
, *pin
;
3310 unsigned int c_cnt
= 0;
3317 * We deal with the case where name already exists in this
3318 * function so the GUI doesn't need to deal with it
3320 name
= gui
->fileselect (_("Save Renumber Annotation File As ..."),
3321 _("Choose a file to record the renumbering to.\n"
3322 "This file may be used to back annotate the\n"
3323 "change to the schematics.\n"),
3324 default_file
, ".eco", "eco",
3334 free (default_file
);
3335 default_file
= NULL
;
3340 default_file
= strdup (name
);
3343 if ((out
= fopen (name
, "r")))
3346 if (!gui
->confirm_dialog (_("File exists! Ok to overwrite?"), 0))
3348 if (free_name
&& name
)
3354 if ((out
= fopen (name
, "w")) == NULL
)
3356 Message (_("Could not open %s\n"), name
);
3357 if (free_name
&& name
)
3362 if (free_name
&& name
)
3365 fprintf (out
, "*COMMENT* PCB Annotation File\n");
3366 fprintf (out
, "*FILEVERSION* 20061031\n");
3369 * Make a first pass through all of the elements and sort them out
3370 * by location on the board. While here we also collect a list of
3373 * We'll actually renumber things in the 2nd pass.
3375 element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementType
*));
3376 locked_element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementType
*));
3377 was
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3378 is
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3379 if (element_list
== NULL
|| locked_element_list
== NULL
|| was
== NULL
3382 fprintf (stderr
, "calloc() failed in %s\n", __FUNCTION__
);
3389 ELEMENT_LOOP (PCB
->Data
);
3391 if (TEST_FLAG (LOCKFLAG
, element
->Name
) || TEST_FLAG (LOCKFLAG
, element
))
3394 * add to the list of locked elements which we won't try to
3395 * renumber and whose reference designators are now reserved.
3398 "*WARN* Element \"%s\" at %$md is locked and will not be renumbered.\n",
3399 UNKNOWN (NAMEONPCB_NAME (element
)), element
->MarkX
, element
->MarkY
);
3400 locked_element_list
[lock_cnt
] = element
;
3406 /* count of devices which will be renumbered */
3409 /* search for correct position in the list */
3411 while (element_list
[i
] && element
->MarkY
> element_list
[i
]->MarkY
)
3415 * We have found the position where we have the first element that
3416 * has the same Y value or a lower Y value. Now move forward if
3417 * needed through the X values
3419 while (element_list
[i
]
3420 && element
->MarkY
== element_list
[i
]->MarkY
3421 && element
->MarkX
> element_list
[i
]->MarkX
)
3424 for (j
= cnt
- 1; j
> i
; j
--)
3426 element_list
[j
] = element_list
[j
- 1];
3428 element_list
[i
] = element
;
3435 * Now that the elements are sorted by board position, we go through
3436 * and renumber them.
3440 * turn off the flag which requires unique names so it doesn't get
3441 * in our way. When we're done with the renumber we will have unique
3444 unique
= TEST_FLAG (UNIQUENAMEFLAG
, PCB
);
3445 CLEAR_FLAG (UNIQUENAMEFLAG
, PCB
);
3447 cnt_list
= (struct _cnt_list
*)calloc (cnt_list_sz
, sizeof (struct _cnt_list
));
3448 for (i
= 0; i
< cnt
; i
++)
3450 /* If there is no refdes, maybe just spit out a warning */
3451 if (NAMEONPCB_NAME (element_list
[i
]))
3453 /* figure out the prefix */
3454 tmps
= strdup (NAMEONPCB_NAME (element_list
[i
]));
3456 while (tmps
[j
] && (tmps
[j
] < '0' || tmps
[j
] > '9')
3461 /* check the counter for this prefix */
3463 cnt_list
[j
].name
&& (strcmp (cnt_list
[j
].name
, tmps
) != 0)
3464 && j
< cnt_list_sz
; j
++);
3466 /* grow the list if needed */
3467 if (j
== cnt_list_sz
)
3470 cnt_list
= (struct _cnt_list
*)realloc (cnt_list
, cnt_list_sz
);
3471 if (cnt_list
== NULL
)
3473 fprintf (stderr
, _("realloc failed() in %s\n"), __FUNCTION__
);
3476 /* zero out the memory that we added */
3477 for (tmpi
= j
; tmpi
< cnt_list_sz
; tmpi
++)
3479 cnt_list
[tmpi
].name
= NULL
;
3480 cnt_list
[tmpi
].cnt
= 0;
3485 * start a new counter if we don't have a counter for this
3488 if (!cnt_list
[j
].name
)
3490 cnt_list
[j
].name
= strdup (tmps
);
3491 cnt_list
[j
].cnt
= 0;
3495 * check to see if the new refdes is already used by a
3504 /* space for the prefix plus 1 digit plus the '\0' */
3505 sz
= strlen (cnt_list
[j
].name
) + 2;
3507 /* and 1 more per extra digit needed to hold the number */
3508 tmpi
= cnt_list
[j
].cnt
;
3514 tmps
= (char *)malloc (sz
* sizeof (char));
3515 sprintf (tmps
, "%s%d", cnt_list
[j
].name
, (int) cnt_list
[j
].cnt
);
3518 * now compare to the list of reserved (by locked
3521 for (k
= 0; k
< lock_cnt
; k
++)
3524 (UNKNOWN (NAMEONPCB_NAME (locked_element_list
[k
])),
3535 if (strcmp (tmps
, NAMEONPCB_NAME (element_list
[i
])) != 0)
3537 fprintf (out
, "*RENAME* \"%s\" \"%s\"\n",
3538 NAMEONPCB_NAME (element_list
[i
]), tmps
);
3540 /* add this rename to our table of renames so we can update the netlist */
3541 was
[c_cnt
] = strdup (NAMEONPCB_NAME (element_list
[i
]));
3542 is
[c_cnt
] = strdup (tmps
);
3545 AddObjectToChangeNameUndoList (ELEMENT_TYPE
, NULL
, NULL
,
3547 NAMEONPCB_NAME (element_list
3550 ChangeObjectName (ELEMENT_TYPE
, element_list
[i
], NULL
, NULL
,
3554 /* we don't free tmps in this case because it is used */
3561 pcb_fprintf (out
, "*WARN* Element at %$md has no name.\n",
3562 element_list
[i
]->MarkX
, element_list
[i
]->MarkY
);
3569 /* restore the unique flag setting */
3571 SET_FLAG (UNIQUENAMEFLAG
, PCB
);
3576 /* update the netlist */
3577 AddNetlistLibToUndoList (&(PCB
->NetlistLib
));
3579 /* iterate over each net */
3580 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
3583 /* iterate over each pin on the net */
3584 for (j
= 0; j
< PCB
->NetlistLib
.Menu
[i
].EntryN
; j
++)
3587 /* figure out the pin number part from strings like U3-21 */
3588 tmps
= strdup (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3589 for (k
= 0; tmps
[k
] && tmps
[k
] != '-'; k
++);
3593 /* iterate over the list of changed reference designators */
3594 for (k
= 0; k
< c_cnt
; k
++)
3597 * if the pin needs to change, change it and quit
3598 * searching in the list.
3600 if (strcmp (tmps
, was
[k
]) == 0)
3602 free (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3603 PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
=
3604 (char *)malloc ((strlen (is
[k
]) + strlen (pin
) +
3605 2) * sizeof (char));
3606 sprintf (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
,
3607 "%s-%s", is
[k
], pin
);
3615 for (k
= 0; k
< c_cnt
; k
++)
3622 IncrementUndoSerialNumber ();
3623 SetChangedFlag (true);
3626 free (locked_element_list
);
3627 free (element_list
);
3635 /* --------------------------------------------------------------------------- */
3637 static const char ripup_syntax
[] = N_("RipUp(All|Selected|Element)");
3639 static const char ripup_help
[] =
3640 N_("Ripup auto-routed tracks, or convert an element to parts.");
3642 /* %start-doc actions RipUp
3647 Removes all lines and vias which were created by the autorouter.
3650 Removes all selected lines and vias which were created by the
3654 Converts the element under the cursor to parts (vias and lines). Note
3655 that this uses the highest numbered paste buffer.
3662 ActionRipUp (int argc
, char **argv
, Coord x
, Coord y
)
3664 char *function
= ARG (0);
3665 bool changed
= false;
3669 switch (GetFunctionID (function
))
3672 ALLLINE_LOOP (PCB
->Data
);
3674 if (TEST_FLAG (AUTOFLAG
, line
) && !TEST_FLAG (LOCKFLAG
, line
))
3676 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3681 ALLARC_LOOP (PCB
->Data
);
3683 if (TEST_FLAG (AUTOFLAG
, arc
) && !TEST_FLAG (LOCKFLAG
, arc
))
3685 RemoveObject (ARC_TYPE
, layer
, arc
, arc
);
3690 VIA_LOOP (PCB
->Data
);
3692 if (TEST_FLAG (AUTOFLAG
, via
) && !TEST_FLAG (LOCKFLAG
, via
))
3694 RemoveObject (VIA_TYPE
, via
, via
, via
);
3702 IncrementUndoSerialNumber ();
3703 SetChangedFlag (true);
3707 VISIBLELINE_LOOP (PCB
->Data
);
3709 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, line
)
3710 && !TEST_FLAG (LOCKFLAG
, line
))
3712 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3718 VIA_LOOP (PCB
->Data
);
3720 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, via
)
3721 && !TEST_FLAG (LOCKFLAG
, via
))
3723 RemoveObject (VIA_TYPE
, via
, via
, via
);
3730 IncrementUndoSerialNumber ();
3731 SetChangedFlag (true);
3736 void *ptr1
, *ptr2
, *ptr3
;
3738 if (SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
3739 &ptr1
, &ptr2
, &ptr3
) != NO_TYPE
)
3741 Note
.Buffer
= Settings
.BufferNumber
;
3742 SetBufferNumber (MAX_BUFFER
- 1);
3743 ClearBuffer (PASTEBUFFER
);
3744 CopyObjectToBuffer (PASTEBUFFER
->Data
, PCB
->Data
,
3745 ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3746 SmashBufferElement (PASTEBUFFER
);
3749 SaveUndoSerialNumber ();
3750 EraseObject (ELEMENT_TYPE
, ptr1
, ptr1
);
3751 MoveObjectToRemoveUndoList (ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3752 RestoreUndoSerialNumber ();
3753 CopyPastebufferToLayout (0, 0);
3754 SetBufferNumber (Note
.Buffer
);
3755 SetChangedFlag (true);
3764 /* --------------------------------------------------------------------------- */
3766 static const char addrats_syntax
[] = N_("AddRats(AllRats|SelectedRats|Close)");
3768 static const char addrats_help
[] =
3769 N_("Add one or more rat lines to the board.");
3771 /* %start-doc actions AddRats
3776 Create rat lines for all loaded nets that aren't already connected on
3780 Similarly, but only add rat lines for nets connected to selected pins
3784 Selects the shortest unselected rat on the board.
3791 ActionAddRats (int argc
, char **argv
, Coord x
, Coord y
)
3793 char *function
= ARG (0);
3799 if (Settings
.RatWarn
)
3801 switch (GetFunctionID (function
))
3804 if (AddAllRats (false, NULL
))
3805 SetChangedFlag (true);
3807 case F_SelectedRats
:
3809 if (AddAllRats (true, NULL
))
3810 SetChangedFlag (true);
3813 small
= SQUARE (MAX_COORD
);
3815 RAT_LOOP (PCB
->Data
);
3817 if (TEST_FLAG (SELECTEDFLAG
, line
))
3819 len
= SQUARE (line
->Point1
.X
- line
->Point2
.X
) +
3820 SQUARE (line
->Point1
.Y
- line
->Point2
.Y
);
3830 AddObjectToFlagUndoList (RATLINE_TYPE
, shorty
, shorty
, shorty
);
3831 SET_FLAG (SELECTEDFLAG
, shorty
);
3834 CenterDisplay ((shorty
->Point2
.X
+ shorty
->Point1
.X
) / 2,
3835 (shorty
->Point2
.Y
+ shorty
->Point1
.Y
) / 2,
3844 /* --------------------------------------------------------------------------- */
3846 static const char delete_syntax
[] =
3847 N_("Delete(Object|Selected)\n"
3848 "Delete(AllRats|SelectedRats)");
3850 static const char delete_help
[] = N_("Delete stuff.");
3852 /* %start-doc actions Delete
3857 ActionDelete (int argc
, char **argv
, Coord x
, Coord y
)
3859 char *function
= ARG (0);
3860 int id
= GetFunctionID (function
);
3862 Note
.X
= Crosshair
.X
;
3863 Note
.Y
= Crosshair
.Y
;
3865 if (id
== -1) /* no arg */
3867 if (RemoveSelected() == false)
3875 SetMode(REMOVE_MODE
);
3883 if (DeleteRats (false))
3884 SetChangedFlag (true);
3886 case F_SelectedRats
:
3887 if (DeleteRats (true))
3888 SetChangedFlag (true);
3895 /* --------------------------------------------------------------------------- */
3897 static const char deleterats_syntax
[] =
3898 N_("DeleteRats(AllRats|Selected|SelectedRats)");
3900 static const char deleterats_help
[] = N_("Delete rat lines.");
3902 /* %start-doc actions DeleteRats
3907 ActionDeleteRats (int argc
, char **argv
, Coord x
, Coord y
)
3909 char *function
= ARG (0);
3912 if (Settings
.RatWarn
)
3914 switch (GetFunctionID (function
))
3917 if (DeleteRats (false))
3918 SetChangedFlag (true);
3920 case F_SelectedRats
:
3922 if (DeleteRats (true))
3923 SetChangedFlag (true);
3930 /* --------------------------------------------------------------------------- */
3932 static const char autoplace_syntax
[] = N_("AutoPlaceSelected()");
3934 static const char autoplace_help
[] = N_("Auto-place selected components.");
3936 /* %start-doc actions AutoPlaceSelected
3938 Attempts to re-arrange the selected components such that the nets
3939 connecting them are minimized. Note that you cannot undo this.
3944 ActionAutoPlaceSelected (int argc
, char **argv
, Coord x
, Coord y
)
3947 if (gui
->confirm_dialog (_("Auto-placement can NOT be undone.\n"
3948 "Do you want to continue anyway?\n"), 0))
3950 if (AutoPlaceSelected ())
3951 SetChangedFlag (true);
3956 /* --------------------------------------------------------------------------- */
3958 static const char autoroute_syntax
[] = N_("AutoRoute(AllRats|SelectedRats)");
3960 static const char autoroute_help
[] = N_("Auto-route some or all rat lines.");
3962 /* %start-doc actions AutoRoute
3967 Attempt to autoroute all rats.
3970 Attempt to autoroute the selected rats.
3974 Before autorouting, it's important to set up a few things. First,
3975 make sure any layers you aren't using are disabled, else the
3976 autorouter may use them. Next, make sure the current line and via
3977 styles are set accordingly. Last, make sure "new lines clear
3978 polygons" is set, in case you eventually want to add a copper pour.
3980 Autorouting takes a while. During this time, the program may not be
3986 ActionAutoRoute (int argc
, char **argv
, Coord x
, Coord y
)
3988 char *function
= ARG (0);
3990 if (function
) /* one parameter */
3992 switch (GetFunctionID (function
))
3995 if (AutoRoute (false))
3996 SetChangedFlag (true);
3998 case F_SelectedRats
:
4000 if (AutoRoute (true))
4001 SetChangedFlag (true);
4008 /* --------------------------------------------------------------------------- */
4010 static const char markcrosshair_syntax
[] =
4011 N_("MarkCrosshair()\n"
4012 "MarkCrosshair(Center)");
4014 static const char markcrosshair_help
[] = N_("Set/Reset the Crosshair mark.");
4016 /* %start-doc actions MarkCrosshair
4018 The ``mark'' is a small X-shaped target on the display which is
4019 treated like a second origin (the normal origin is the upper let
4020 corner of the board). The GUI will display a second set of
4021 coordinates for this mark, which tells you how far you are from it.
4023 If no argument is given, the mark is toggled - disabled if it was
4024 enabled, or enabled at the current cursor position of disabled. If
4025 the @code{Center} argument is given, the mark is moved to the current
4031 ActionMarkCrosshair (int argc
, char **argv
, Coord x
, Coord y
)
4033 char *function
= ARG (0);
4034 if (!function
|| !*function
)
4038 notify_mark_change (false);
4039 Marked
.status
= false;
4040 notify_mark_change (true);
4044 notify_mark_change (false);
4045 Marked
.status
= false;
4046 Marked
.status
= true;
4047 Marked
.X
= Crosshair
.X
;
4048 Marked
.Y
= Crosshair
.Y
;
4049 notify_mark_change (true);
4052 else if (GetFunctionID (function
) == F_Center
)
4054 notify_mark_change (false);
4055 Marked
.status
= true;
4056 Marked
.X
= Crosshair
.X
;
4057 Marked
.Y
= Crosshair
.Y
;
4058 notify_mark_change (true);
4063 /* --------------------------------------------------------------------------- */
4065 static const char changesize_syntax
[] =
4066 N_("ChangeSize(Object, delta)\n"
4067 "ChangeSize(SelectedObjects|Selected, delta)\n"
4068 "ChangeSize(SelectedLines|SelectedPins|SelectedVias, delta)\n"
4069 "ChangeSize(SelectedPads|SelectedTexts|SelectedNames, delta)\n"
4070 "ChangeSize(SelectedElements, delta)");
4072 static const char changesize_help
[] = N_("Changes the size of objects.");
4074 /* %start-doc actions ChangeSize
4076 For lines and arcs, this changes the width. For pins and vias, this
4077 changes the overall diameter of the copper annulus. For pads, this
4078 changes the width and, indirectly, the length. For texts and names,
4079 this changes the scaling factor. For elements, this changes the width
4080 of the silk layer lines and arcs for this element.
4085 ActionChangeSize (int argc
, char **argv
, Coord x
, Coord y
)
4087 char *function
= ARG (0);
4088 char *delta
= ARG (1);
4089 char *units
= ARG (2);
4090 bool absolute
; /* indicates if absolute size is given */
4093 if (function
&& delta
)
4095 value
= GetValue (delta
, units
, &absolute
);
4097 value
= delta
[0] == '-' ? -Settings
.increments
->size
4098 : Settings
.increments
->size
;
4099 switch (GetFunctionID (function
))
4104 void *ptr1
, *ptr2
, *ptr3
;
4107 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
4108 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4109 if (TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
4110 Message (_("Sorry, the object is locked\n"));
4111 if (ChangeObjectSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4112 SetChangedFlag (true);
4116 case F_SelectedVias
:
4117 if (ChangeSelectedSize (VIA_TYPE
, value
, absolute
))
4118 SetChangedFlag (true);
4121 case F_SelectedPins
:
4122 if (ChangeSelectedSize (PIN_TYPE
, value
, absolute
))
4123 SetChangedFlag (true);
4126 case F_SelectedPads
:
4127 if (ChangeSelectedSize (PAD_TYPE
, value
, absolute
))
4128 SetChangedFlag (true);
4131 case F_SelectedArcs
:
4132 if (ChangeSelectedSize (ARC_TYPE
, value
, absolute
))
4133 SetChangedFlag (true);
4136 case F_SelectedLines
:
4137 if (ChangeSelectedSize (LINE_TYPE
, value
, absolute
))
4138 SetChangedFlag (true);
4141 case F_SelectedTexts
:
4142 if (ChangeSelectedSize (TEXT_TYPE
, value
, absolute
))
4143 SetChangedFlag (true);
4146 case F_SelectedNames
:
4147 if (ChangeSelectedSize (ELEMENTNAME_TYPE
, value
, absolute
))
4148 SetChangedFlag (true);
4151 case F_SelectedElements
:
4152 if (ChangeSelectedSize (ELEMENT_TYPE
, value
, absolute
))
4153 SetChangedFlag (true);
4157 case F_SelectedObjects
:
4158 if (ChangeSelectedSize (CHANGESIZE_TYPES
, value
, absolute
))
4159 SetChangedFlag (true);
4166 /* --------------------------------------------------------------------------- */
4168 static const char changedrillsize_syntax
[] =
4169 N_("ChangeDrillSize(Object, delta)\n"
4170 "ChangeDrillSize(SelectedPins|SelectedVias|Selected|SelectedObjects, delta)");
4172 static const char changedrillsize_help
[] =
4173 N_("Changes the drilling hole size of objects.");
4175 /* %start-doc actions ChangeDrillSize
4180 ActionChange2ndSize (int argc
, char **argv
, Coord x
, Coord y
)
4182 char *function
= ARG (0);
4183 char *delta
= ARG (1);
4184 char *units
= ARG (2);
4188 if (function
&& delta
)
4190 value
= GetValue (delta
, units
, &absolute
);
4191 switch (GetFunctionID (function
))
4196 void *ptr1
, *ptr2
, *ptr3
;
4198 gui
->get_coords (_("Select an Object"), &x
, &y
);
4200 SearchScreen (x
, y
, CHANGE2NDSIZE_TYPES
,
4201 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4202 if (ChangeObject2ndSize
4203 (type
, ptr1
, ptr2
, ptr3
, value
, absolute
, true))
4204 SetChangedFlag (true);
4208 case F_SelectedVias
:
4209 if (ChangeSelected2ndSize (VIA_TYPE
, value
, absolute
))
4210 SetChangedFlag (true);
4213 case F_SelectedPins
:
4214 if (ChangeSelected2ndSize (PIN_TYPE
, value
, absolute
))
4215 SetChangedFlag (true);
4218 case F_SelectedObjects
:
4219 if (ChangeSelected2ndSize (PIN_TYPES
, value
, absolute
))
4220 SetChangedFlag (true);
4227 /* --------------------------------------------------------------------------- */
4229 static const char changeclearsize_syntax
[] =
4230 N_("ChangeClearSize(Object, delta)\n"
4231 "ChangeClearSize(SelectedPins|SelectedPads|SelectedVias, delta)\n"
4232 "ChangeClearSize(SelectedLines|SelectedArcs, delta\n"
4233 "ChangeClearSize(Selected|SelectedObjects, delta)");
4235 static const char changeclearsize_help
[] =
4236 N_("Changes the clearance size of objects.");
4238 /* %start-doc actions ChangeClearSize
4240 If the solder mask is currently showing, this action changes the
4241 solder mask clearance. If the mask is not showing, this action
4242 changes the polygon clearance.
4247 ActionChangeClearSize (int argc
, char **argv
, Coord x
, Coord y
)
4249 char *function
= ARG (0);
4250 char *delta
= ARG (1);
4251 char *units
= ARG (2);
4255 if (function
&& delta
)
4257 value
= 2 * GetValue (delta
, units
, &absolute
);
4259 value
= delta
[0] == '-' ? -Settings
.increments
->clear
4260 : Settings
.increments
->clear
;
4261 switch (GetFunctionID (function
))
4266 void *ptr1
, *ptr2
, *ptr3
;
4268 gui
->get_coords (_("Select an Object"), &x
, &y
);
4271 CHANGECLEARSIZE_TYPES
, &ptr1
, &ptr2
,
4273 if (ChangeObjectClearSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4274 SetChangedFlag (true);
4277 case F_SelectedVias
:
4278 if (ChangeSelectedClearSize (VIA_TYPE
, value
, absolute
))
4279 SetChangedFlag (true);
4281 case F_SelectedPads
:
4282 if (ChangeSelectedClearSize (PAD_TYPE
, value
, absolute
))
4283 SetChangedFlag (true);
4285 case F_SelectedPins
:
4286 if (ChangeSelectedClearSize (PIN_TYPE
, value
, absolute
))
4287 SetChangedFlag (true);
4289 case F_SelectedLines
:
4290 if (ChangeSelectedClearSize (LINE_TYPE
, value
, absolute
))
4291 SetChangedFlag (true);
4293 case F_SelectedArcs
:
4294 if (ChangeSelectedClearSize (ARC_TYPE
, value
, absolute
))
4295 SetChangedFlag (true);
4298 case F_SelectedObjects
:
4299 if (ChangeSelectedClearSize (CHANGECLEARSIZE_TYPES
, value
, absolute
))
4300 SetChangedFlag (true);
4307 /* --------------------------------------------------------------------------- */
4309 static const char minmaskgap_syntax
[] =
4310 N_("MinMaskGap(delta)\n"
4311 "MinMaskGap(Selected, delta)");
4313 static const char minmaskgap_help
[] =
4314 N_("Ensures the mask is a minimum distance from pins and pads.");
4316 /* %start-doc actions MinMaskGap
4318 Checks all specified pins and/or pads, and increases the mask if
4319 needed to ensure a minimum distance between the pin or pad edge and
4325 ActionMinMaskGap (int argc
, char **argv
, Coord x
, Coord y
)
4327 char *function
= ARG (0);
4328 char *delta
= ARG (1);
4329 char *units
= ARG (2);
4337 if (strcasecmp (function
, "Selected") == 0)
4338 flags
= SELECTEDFLAG
;
4345 value
= 2 * GetValue (delta
, units
, &absolute
);
4347 SaveUndoSerialNumber ();
4348 ELEMENT_LOOP (PCB
->Data
);
4352 if (!TEST_FLAGS (flags
, pin
) || ! pin
->Mask
)
4355 thickness
= pin
->DrillingHole
;
4356 if (pin
->Thickness
> thickness
)
4357 thickness
= pin
->Thickness
;
4360 if (pin
->Mask
< thickness
)
4362 ChangeObjectMaskSize (PIN_TYPE
, element
, pin
, 0, thickness
, 1);
4363 RestoreUndoSerialNumber ();
4369 if (!TEST_FLAGS (flags
, pad
) || ! pad
->Mask
)
4371 if (pad
->Mask
< pad
->Thickness
+ value
)
4373 ChangeObjectMaskSize (PAD_TYPE
, element
, pad
, 0,
4374 pad
->Thickness
+ value
, 1);
4375 RestoreUndoSerialNumber ();
4381 VIA_LOOP (PCB
->Data
);
4383 if (!TEST_FLAGS (flags
, via
) || ! via
->Mask
)
4386 thickness
= via
->DrillingHole
;
4387 if (via
->Thickness
> thickness
)
4388 thickness
= via
->Thickness
;
4391 if (via
->Mask
< thickness
)
4393 ChangeObjectMaskSize (VIA_TYPE
, via
, 0, 0, thickness
, 1);
4394 RestoreUndoSerialNumber ();
4398 RestoreUndoSerialNumber ();
4399 IncrementUndoSerialNumber ();
4403 /* --------------------------------------------------------------------------- */
4405 static const char mincleargap_syntax
[] =
4406 N_("MinClearGap(delta)\n"
4407 "MinClearGap(Selected, delta)");
4409 static const char mincleargap_help
[] =
4410 N_("Ensures that polygons are a minimum distance from objects.");
4412 /* %start-doc actions MinClearGap
4414 Checks all specified objects, and increases the polygon clearance if
4415 needed to ensure a minimum distance between their edges and the
4421 ActionMinClearGap (int argc
, char **argv
, Coord x
, Coord y
)
4423 char *function
= ARG (0);
4424 char *delta
= ARG (1);
4425 char *units
= ARG (2);
4432 if (strcasecmp (function
, "Selected") == 0)
4433 flags
= SELECTEDFLAG
;
4440 value
= 2 * GetValue (delta
, units
, &absolute
);
4442 SaveUndoSerialNumber ();
4443 ELEMENT_LOOP (PCB
->Data
);
4447 if (!TEST_FLAGS (flags
, pin
))
4449 if (pin
->Clearance
< value
)
4451 ChangeObjectClearSize (PIN_TYPE
, element
, pin
, 0,
4453 RestoreUndoSerialNumber ();
4459 if (!TEST_FLAGS (flags
, pad
))
4461 if (pad
->Clearance
< value
)
4463 ChangeObjectClearSize (PAD_TYPE
, element
, pad
, 0,
4465 RestoreUndoSerialNumber ();
4471 VIA_LOOP (PCB
->Data
);
4473 if (!TEST_FLAGS (flags
, via
))
4475 if (via
->Clearance
< value
)
4477 ChangeObjectClearSize (VIA_TYPE
, via
, 0, 0, value
, 1);
4478 RestoreUndoSerialNumber ();
4482 ALLLINE_LOOP (PCB
->Data
);
4484 if (!TEST_FLAGS (flags
, line
))
4486 if (line
->Clearance
< value
)
4488 ChangeObjectClearSize (LINE_TYPE
, layer
, line
, 0, value
, 1);
4489 RestoreUndoSerialNumber ();
4493 ALLARC_LOOP (PCB
->Data
);
4495 if (!TEST_FLAGS (flags
, arc
))
4497 if (arc
->Clearance
< value
)
4499 ChangeObjectClearSize (ARC_TYPE
, layer
, arc
, 0, value
, 1);
4500 RestoreUndoSerialNumber ();
4504 RestoreUndoSerialNumber ();
4505 IncrementUndoSerialNumber ();
4509 /* --------------------------------------------------------------------------- */
4511 static const char changepinname_syntax
[] =
4512 N_("ChangePinName(ElementName,PinNumber,PinName)");
4514 static const char changepinname_help
[] =
4515 N_("Sets the name of a specific pin on a specific element.");
4517 /* %start-doc actions ChangePinName
4519 This can be especially useful for annotating pin names from a
4520 schematic to the layout without requiring knowledge of the pcb file
4524 ChangePinName(U3, 7, VCC)
4530 ActionChangePinName (int argc
, char **argv
, Coord x
, Coord y
)
4533 char *refdes
, *pinnum
, *pinname
;
4537 AFAIL (changepinname
);
4544 ELEMENT_LOOP (PCB
->Data
);
4546 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
4550 if (NSTRCMP (pinnum
, pin
->Number
) == 0)
4552 AddObjectToChangeNameUndoList (PIN_TYPE
, NULL
, NULL
,
4555 * Note: we can't free() pin->Name first because
4556 * it is used in the undo list
4558 pin
->Name
= strdup (pinname
);
4559 SetChangedFlag (true);
4567 if (NSTRCMP (pinnum
, pad
->Number
) == 0)
4569 AddObjectToChangeNameUndoList (PAD_TYPE
, NULL
, NULL
,
4572 * Note: we can't free() pad->Name first because
4573 * it is used in the undo list
4575 pad
->Name
= strdup (pinname
);
4576 SetChangedFlag (true);
4585 * done with our action so increment the undo # if we actually
4591 defer_needs_update
= 1;
4594 IncrementUndoSerialNumber ();
4595 gui
->invalidate_all ();
4602 /* --------------------------------------------------------------------------- */
4604 static const char changename_syntax
[] =
4605 N_("ChangeName(Object)\n"
4606 "ChangeName(Layout|Layer)");
4608 static const char changename_help
[] = N_("Sets the name of objects.");
4610 /* %start-doc actions ChangeName
4615 Changes the name of the element under the cursor.
4618 Changes the name of the layout. This is printed on the fab drawings.
4621 Changes the name of the currently active layer.
4628 ActionChangeName (int argc
, char **argv
, Coord x
, Coord y
)
4630 char *function
= ARG (0);
4635 switch (GetFunctionID (function
))
4637 /* change the name of an object */
4641 void *ptr1
, *ptr2
, *ptr3
;
4643 gui
->get_coords (_("Select an Object"), &x
, &y
);
4645 SearchScreen (x
, y
, CHANGENAME_TYPES
,
4646 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4648 SaveUndoSerialNumber ();
4649 if (QueryInputAndChangeObjectName (type
, ptr1
, ptr2
, ptr3
))
4651 SetChangedFlag (true);
4652 if (type
== ELEMENT_TYPE
)
4654 RubberbandType
*ptr
;
4657 RestoreUndoSerialNumber ();
4658 Crosshair
.AttachedObject
.RubberbandN
= 0;
4659 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
4660 ptr
= Crosshair
.AttachedObject
.Rubberband
;
4661 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
;
4665 EraseRat ((RatType
*) ptr
->Line
);
4666 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
4667 ptr
->Line
, ptr
->Line
,
4670 IncrementUndoSerialNumber ();
4678 /* change the layout's name */
4681 gui
->prompt_for (_("Enter the layout name:"), EMPTY (PCB
->Name
));
4682 /* NB: ChangeLayoutName takes ownership of the passed memory */
4683 if (name
&& ChangeLayoutName (name
))
4684 SetChangedFlag (true);
4687 /* change the name of the active layer */
4689 name
= gui
->prompt_for (_("Enter the layer name:"),
4690 EMPTY (CURRENT
->Name
));
4691 /* NB: ChangeLayerName takes ownership of the passed memory */
4692 if (name
&& ChangeLayerName (CURRENT
, name
))
4693 SetChangedFlag (true);
4701 /* --------------------------------------------------------------------------- */
4703 static const char morphpolygon_syntax
[] = N_("MorphPolygon(Object|Selected)");
4705 static const char morphpolygon_help
[] =
4706 N_("Converts dead polygon islands into separate polygons.");
4708 /* %start-doc actions MorphPolygon
4710 If a polygon is divided into unconnected "islands", you can use
4711 this command to convert the otherwise disappeared islands into
4712 separate polygons. Be sure the cursor is over a portion of the
4713 polygon that remains visible. Very small islands that may flake
4714 off are automatically deleted.
4719 ActionMorphPolygon (int argc
, char **argv
, Coord x
, Coord y
)
4721 char *function
= ARG (0);
4724 switch (GetFunctionID (function
))
4729 void *ptr1
, *ptr2
, *ptr3
;
4731 gui
->get_coords (_("Select an Object"), &x
, &y
);
4732 if ((type
= SearchScreen (x
, y
, POLYGON_TYPE
,
4733 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4735 MorphPolygon ((LayerType
*) ptr1
, (PolygonType
*) ptr3
);
4737 IncrementUndoSerialNumber ();
4742 case F_SelectedObjects
:
4743 ALLPOLYGON_LOOP (PCB
->Data
);
4745 if (TEST_FLAG (SELECTEDFLAG
, polygon
))
4746 MorphPolygon (layer
, polygon
);
4750 IncrementUndoSerialNumber ();
4757 /* --------------------------------------------------------------------------- */
4759 static const char togglehidename_syntax
[] =
4760 N_("ToggleHideName(Object|SelectedElements)");
4762 static const char togglehidename_help
[] =
4763 N_("Toggles the visibility of element names.");
4765 /* %start-doc actions ToggleHideName
4767 If names are hidden you won't see them on the screen and they will not
4768 appear on the silk layer when you print the layout.
4773 ActionToggleHideName (int argc
, char **argv
, Coord x
, Coord y
)
4775 char *function
= ARG (0);
4776 if (function
&& PCB
->ElementOn
)
4778 switch (GetFunctionID (function
))
4783 void *ptr1
, *ptr2
, *ptr3
;
4785 gui
->get_coords (_("Select an Object"), &x
, &y
);
4786 if ((type
= SearchScreen (x
, y
, ELEMENT_TYPE
,
4787 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4789 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr3
);
4790 EraseElementName ((ElementType
*) ptr2
);
4791 TOGGLE_FLAG (HIDENAMEFLAG
, (ElementType
*) ptr2
);
4792 DrawElementName ((ElementType
*) ptr2
);
4794 IncrementUndoSerialNumber ();
4798 case F_SelectedElements
:
4801 bool changed
= false;
4802 ELEMENT_LOOP (PCB
->Data
);
4804 if ((TEST_FLAG (SELECTEDFLAG
, element
) ||
4805 TEST_FLAG (SELECTEDFLAG
,
4806 &NAMEONPCB_TEXT (element
)))
4807 && (FRONT (element
) || PCB
->InvisibleObjectsOn
))
4809 AddObjectToFlagUndoList (ELEMENT_TYPE
, element
,
4811 EraseElementName (element
);
4812 TOGGLE_FLAG (HIDENAMEFLAG
, element
);
4813 DrawElementName (element
);
4821 IncrementUndoSerialNumber ();
4829 /* --------------------------------------------------------------------------- */
4831 static const char changejoin_syntax
[] =
4832 N_("ChangeJoin(ToggleObject|SelectedLines|SelectedArcs|Selected)");
4834 static const char changejoin_help
[] =
4835 N_("Changes the join (clearance through polygons) of objects.");
4837 /* %start-doc actions ChangeJoin
4839 The join flag determines whether a line or arc, drawn to intersect a
4840 polygon, electrically connects to the polygon or not. When joined,
4841 the line/arc is simply drawn over the polygon, making an electrical
4842 connection. When not joined, a gap is drawn between the line and the
4843 polygon, insulating them from each other.
4848 ActionChangeJoin (int argc
, char **argv
, Coord x
, Coord y
)
4850 char *function
= ARG (0);
4853 switch (GetFunctionID (function
))
4855 case F_ToggleObject
:
4859 void *ptr1
, *ptr2
, *ptr3
;
4861 gui
->get_coords (_("Select an Object"), &x
, &y
);
4863 SearchScreen (x
, y
, CHANGEJOIN_TYPES
,
4864 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4865 if (ChangeObjectJoin (type
, ptr1
, ptr2
, ptr3
))
4866 SetChangedFlag (true);
4870 case F_SelectedLines
:
4871 if (ChangeSelectedJoin (LINE_TYPE
))
4872 SetChangedFlag (true);
4875 case F_SelectedArcs
:
4876 if (ChangeSelectedJoin (ARC_TYPE
))
4877 SetChangedFlag (true);
4881 case F_SelectedObjects
:
4882 if (ChangeSelectedJoin (CHANGEJOIN_TYPES
))
4883 SetChangedFlag (true);
4890 /* --------------------------------------------------------------------------- */
4892 static const char changesquare_syntax
[] =
4893 N_("ChangeSquare(ToggleObject)\n"
4894 "ChangeSquare(SelectedElements|SelectedPins)\n"
4895 "ChangeSquare(Selected|SelectedObjects)");
4897 static const char changesquare_help
[] =
4898 N_("Changes the square flag of pins and pads.");
4900 /* %start-doc actions ChangeSquare
4902 Note that @code{Pins} means both pins and pads.
4909 ActionChangeSquare (int argc
, char **argv
, Coord x
, Coord y
)
4911 char *function
= ARG (0);
4914 switch (GetFunctionID (function
))
4916 case F_ToggleObject
:
4920 void *ptr1
, *ptr2
, *ptr3
;
4922 gui
->get_coords (_("Select an Object"), &x
, &y
);
4924 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4925 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4926 if (ChangeObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4927 SetChangedFlag (true);
4931 case F_SelectedElements
:
4932 if (ChangeSelectedSquare (ELEMENT_TYPE
))
4933 SetChangedFlag (true);
4936 case F_SelectedPins
:
4937 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4938 SetChangedFlag (true);
4942 case F_SelectedObjects
:
4943 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4944 SetChangedFlag (true);
4951 /* --------------------------------------------------------------------------- */
4953 static const char setsquare_syntax
[] =
4954 N_("SetSquare(ToggleObject|SelectedElements|SelectedPins)");
4956 static const char setsquare_help
[] = N_("sets the square-flag of objects.");
4958 /* %start-doc actions SetSquare
4960 Note that @code{Pins} means pins and pads.
4967 ActionSetSquare (int argc
, char **argv
, Coord x
, Coord y
)
4969 char *function
= ARG (0);
4970 if (function
&& *function
)
4972 switch (GetFunctionID (function
))
4974 case F_ToggleObject
:
4978 void *ptr1
, *ptr2
, *ptr3
;
4980 gui
->get_coords (_("Select an Object"), &x
, &y
);
4982 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4983 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4984 if (SetObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4985 SetChangedFlag (true);
4989 case F_SelectedElements
:
4990 if (SetSelectedSquare (ELEMENT_TYPE
))
4991 SetChangedFlag (true);
4994 case F_SelectedPins
:
4995 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4996 SetChangedFlag (true);
5000 case F_SelectedObjects
:
5001 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
5002 SetChangedFlag (true);
5009 /* --------------------------------------------------------------------------- */
5011 static const char clearsquare_syntax
[] =
5012 N_("ClearSquare(ToggleObject|SelectedElements|SelectedPins)");
5014 static const char clearsquare_help
[] =
5015 N_("Clears the square-flag of pins and pads.");
5017 /* %start-doc actions ClearSquare
5019 Note that @code{Pins} means pins and pads.
5026 ActionClearSquare (int argc
, char **argv
, Coord x
, Coord y
)
5028 char *function
= ARG (0);
5029 if (function
&& *function
)
5031 switch (GetFunctionID (function
))
5033 case F_ToggleObject
:
5037 void *ptr1
, *ptr2
, *ptr3
;
5039 gui
->get_coords (_("Select an Object"), &x
, &y
);
5041 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
5042 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5043 if (ClrObjectSquare (type
, ptr1
, ptr2
, ptr3
))
5044 SetChangedFlag (true);
5048 case F_SelectedElements
:
5049 if (ClrSelectedSquare (ELEMENT_TYPE
))
5050 SetChangedFlag (true);
5053 case F_SelectedPins
:
5054 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
5055 SetChangedFlag (true);
5059 case F_SelectedObjects
:
5060 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
5061 SetChangedFlag (true);
5068 /* --------------------------------------------------------------------------- */
5070 static const char changeoctagon_syntax
[] =
5071 N_("ChangeOctagon(Object|ToggleObject|SelectedObjects|Selected)\n"
5072 "ChangeOctagon(SelectedElements|SelectedPins|SelectedVias)");
5074 static const char changeoctagon_help
[] =
5075 N_("Changes the octagon-flag of pins and vias.");
5077 /* %start-doc actions ChangeOctagon
5084 ActionChangeOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5086 char *function
= ARG (0);
5089 switch (GetFunctionID (function
))
5091 case F_ToggleObject
:
5095 void *ptr1
, *ptr2
, *ptr3
;
5097 gui
->get_coords (_("Select an Object"), &x
, &y
);
5099 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5100 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5101 if (ChangeObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5102 SetChangedFlag (true);
5106 case F_SelectedElements
:
5107 if (ChangeSelectedOctagon (ELEMENT_TYPE
))
5108 SetChangedFlag (true);
5111 case F_SelectedPins
:
5112 if (ChangeSelectedOctagon (PIN_TYPE
))
5113 SetChangedFlag (true);
5116 case F_SelectedVias
:
5117 if (ChangeSelectedOctagon (VIA_TYPE
))
5118 SetChangedFlag (true);
5122 case F_SelectedObjects
:
5123 if (ChangeSelectedOctagon (PIN_TYPES
))
5124 SetChangedFlag (true);
5131 /* --------------------------------------------------------------------------- */
5133 static const char setoctagon_syntax
[] =
5134 N_("SetOctagon(Object|ToggleObject|SelectedElements|Selected)");
5136 static const char setoctagon_help
[] = N_("Sets the octagon-flag of objects.");
5138 /* %start-doc actions SetOctagon
5145 ActionSetOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5147 char *function
= ARG (0);
5150 switch (GetFunctionID (function
))
5152 case F_ToggleObject
:
5156 void *ptr1
, *ptr2
, *ptr3
;
5158 gui
->get_coords (_("Select an Object"), &x
, &y
);
5160 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5161 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5162 if (SetObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5163 SetChangedFlag (true);
5167 case F_SelectedElements
:
5168 if (SetSelectedOctagon (ELEMENT_TYPE
))
5169 SetChangedFlag (true);
5172 case F_SelectedPins
:
5173 if (SetSelectedOctagon (PIN_TYPE
))
5174 SetChangedFlag (true);
5177 case F_SelectedVias
:
5178 if (SetSelectedOctagon (VIA_TYPE
))
5179 SetChangedFlag (true);
5183 case F_SelectedObjects
:
5184 if (SetSelectedOctagon (PIN_TYPES
))
5185 SetChangedFlag (true);
5192 /* --------------------------------------------------------------------------- */
5194 static const char clearoctagon_syntax
[] =
5195 N_("ClearOctagon(ToggleObject|Object|SelectedObjects|Selected)\n"
5196 "ClearOctagon(SelectedElements|SelectedPins|SelectedVias)");
5198 static const char clearoctagon_help
[] =
5199 N_("Clears the octagon-flag of pins and vias.");
5201 /* %start-doc actions ClearOctagon
5208 ActionClearOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5210 char *function
= ARG (0);
5213 switch (GetFunctionID (function
))
5215 case F_ToggleObject
:
5219 void *ptr1
, *ptr2
, *ptr3
;
5221 gui
->get_coords (_("Select an Object"), &x
, &y
);
5223 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGEOCTAGON_TYPES
,
5224 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5225 if (ClrObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5226 SetChangedFlag (true);
5230 case F_SelectedElements
:
5231 if (ClrSelectedOctagon (ELEMENT_TYPE
))
5232 SetChangedFlag (true);
5235 case F_SelectedPins
:
5236 if (ClrSelectedOctagon (PIN_TYPE
))
5237 SetChangedFlag (true);
5240 case F_SelectedVias
:
5241 if (ClrSelectedOctagon (VIA_TYPE
))
5242 SetChangedFlag (true);
5246 case F_SelectedObjects
:
5247 if (ClrSelectedOctagon (PIN_TYPES
))
5248 SetChangedFlag (true);
5255 /* --------------------------------------------------------------------------- */
5257 static const char changehold_syntax
[] =
5258 N_("ChangeHole(ToggleObject|Object|SelectedVias|Selected)");
5260 static const char changehold_help
[] = N_("Changes the hole flag of objects.");
5262 /* %start-doc actions ChangeHole
5264 The "hole flag" of a via determines whether the via is a
5265 plated-through hole (not set), or an unplated hole (set).
5270 ActionChangeHole (int argc
, char **argv
, Coord x
, Coord y
)
5272 char *function
= ARG (0);
5275 switch (GetFunctionID (function
))
5277 case F_ToggleObject
:
5281 void *ptr1
, *ptr2
, *ptr3
;
5283 gui
->get_coords (_("Select an Object"), &x
, &y
);
5284 if ((type
= SearchScreen (x
, y
, VIA_TYPE
,
5285 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5286 && ChangeHole ((PinType
*) ptr3
))
5287 IncrementUndoSerialNumber ();
5291 case F_SelectedVias
:
5293 if (ChangeSelectedHole ())
5294 SetChangedFlag (true);
5301 /* --------------------------------------------------------------------------- */
5303 static const char changepaste_syntax
[] =
5304 N_("ChangePaste(ToggleObject|Object|SelectedPads|Selected)");
5306 static const char changepaste_help
[] =
5307 N_("Changes the no paste flag of objects.");
5309 /* %start-doc actions ChangePaste
5311 The "no paste flag" of a pad determines whether the solderpaste
5312 stencil will have an opening for the pad (no set) or if there wil be
5313 no solderpaste on the pad (set). This is used for things such as
5319 ActionChangePaste (int argc
, char **argv
, Coord x
, Coord y
)
5321 char *function
= ARG (0);
5324 switch (GetFunctionID (function
))
5326 case F_ToggleObject
:
5330 void *ptr1
, *ptr2
, *ptr3
;
5332 gui
->get_coords (_("Select an Object"), &x
, &y
);
5333 if ((type
= SearchScreen (x
, y
, PAD_TYPE
,
5334 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5335 && ChangePaste ((PadType
*) ptr3
))
5336 IncrementUndoSerialNumber ();
5340 case F_SelectedPads
:
5342 if (ChangeSelectedPaste ())
5343 SetChangedFlag (true);
5350 /* --------------------------------------------------------------------------- */
5352 static const char select_syntax
[] =
5353 N_("Select(Object|ToggleObject)\n"
5354 "Select(All|Block|Connection)\n"
5355 "Select(ElementByName|ObjectByName|PadByName|PinByName)\n"
5356 "Select(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5357 "Select(TextByName|ViaByName|NetByName)\n"
5358 "Select(TextByName|ViaByName|NetByName, Name)\n"
5361 static const char select_help
[] = N_("Toggles or sets the selection.");
5363 /* %start-doc actions Select
5375 These all rely on having a regular expression parser built into
5376 @code{pcb}. If the name is not specified then the user is prompted
5377 for a pattern, and all objects that match the pattern and are of the
5378 type specified are selected.
5382 Selects the object under the cursor.
5385 Selects all objects in a rectangle indicated by the cursor.
5388 Selects all objects on the board.
5391 Selects all connections with the ``found'' flag set.
5394 Selects all connections with the ``connected'' flag set.
5397 Converts the selected objects to an element. This uses the highest
5398 numbered paste buffer.
5405 ActionSelect (int argc
, char **argv
, Coord x
, Coord y
)
5407 char *function
= ARG (0);
5410 switch (GetFunctionID (function
))
5412 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5414 /* select objects by their names */
5415 case F_ElementByName
:
5416 type
= ELEMENT_TYPE
;
5418 case F_ObjectByName
:
5439 char *pattern
= ARG (1);
5443 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5445 if (SelectObjectByName (type
, pattern
, true))
5446 SetChangedFlag (true);
5447 if (ARG (1) == NULL
)
5452 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5454 /* select a single object */
5455 case F_ToggleObject
:
5457 if (SelectObject ())
5458 SetChangedFlag (true);
5461 /* all objects in block */
5466 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5467 Crosshair
.AttachedBox
.Point2
.X
);
5468 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5469 Crosshair
.AttachedBox
.Point2
.Y
);
5470 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5471 Crosshair
.AttachedBox
.Point2
.X
);
5472 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5473 Crosshair
.AttachedBox
.Point2
.Y
);
5474 notify_crosshair_change (false);
5476 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5477 SelectBlock (&box
, true))
5479 SetChangedFlag (true);
5480 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5482 notify_crosshair_change (true);
5486 /* select all visible objects */
5491 box
.X1
= -MAX_COORD
;
5492 box
.Y1
= -MAX_COORD
;
5495 if (SelectBlock (&box
, true))
5496 SetChangedFlag (true);
5500 /* all logical connections */
5502 if (SelectByFlag (FOUNDFLAG
, true))
5505 IncrementUndoSerialNumber ();
5506 SetChangedFlag (true);
5510 /* all physical connections */
5512 if (SelectByFlag (CONNECTEDFLAG
, true))
5515 IncrementUndoSerialNumber ();
5516 SetChangedFlag (true);
5523 Note
.Buffer
= Settings
.BufferNumber
;
5524 SetBufferNumber (MAX_BUFFER
- 1);
5525 ClearBuffer (PASTEBUFFER
);
5526 gui
->get_coords (_("Select the Element's Mark Location"), &x
, &y
);
5527 x
= GridFit (x
, PCB
->Grid
, PCB
->GridOffsetX
);
5528 y
= GridFit (y
, PCB
->Grid
, PCB
->GridOffsetY
);
5529 AddSelectedToBuffer (PASTEBUFFER
, x
, y
, true);
5530 SaveUndoSerialNumber ();
5532 ConvertBufferToElement (PASTEBUFFER
);
5533 RestoreUndoSerialNumber ();
5534 CopyPastebufferToLayout (x
, y
);
5535 SetBufferNumber (Note
.Buffer
);
5547 /* FLAG(have_regex,FlagHaveRegex,0) */
5549 FlagHaveRegex (int parm
)
5551 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5558 /* --------------------------------------------------------------------------- */
5560 static const char unselect_syntax
[] =
5561 N_("Unselect(All|Block|Connection)\n"
5562 "Unselect(ElementByName|ObjectByName|PadByName|PinByName)\n"
5563 "Unselect(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5564 "Unselect(TextByName|ViaByName)\n"
5565 "Unselect(TextByName|ViaByName, Name)\n");
5567 static const char unselect_help
[] =
5568 N_("Unselects the object at the pointer location or the specified objects.");
5570 /* %start-doc actions Unselect
5575 Unselect all objects.
5578 Unselect all objects in a rectangle given by the cursor.
5581 Unselect all connections with the ``found'' flag set.
5590 These all rely on having a regular expression parser built into
5591 @code{pcb}. If the name is not specified then the user is prompted
5592 for a pattern, and all objects that match the pattern and are of the
5593 type specified are unselected.
5601 ActionUnselect (int argc
, char **argv
, Coord x
, Coord y
)
5603 char *function
= ARG (0);
5606 switch (GetFunctionID (function
))
5608 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5610 /* select objects by their names */
5611 case F_ElementByName
:
5612 type
= ELEMENT_TYPE
;
5614 case F_ObjectByName
:
5635 char *pattern
= ARG (1);
5639 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5641 if (SelectObjectByName (type
, pattern
, false))
5642 SetChangedFlag (true);
5643 if (ARG (1) == NULL
)
5648 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5650 /* all objects in block */
5655 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5656 Crosshair
.AttachedBox
.Point2
.X
);
5657 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5658 Crosshair
.AttachedBox
.Point2
.Y
);
5659 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5660 Crosshair
.AttachedBox
.Point2
.X
);
5661 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5662 Crosshair
.AttachedBox
.Point2
.Y
);
5663 notify_crosshair_change (false);
5665 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5666 SelectBlock (&box
, false))
5668 SetChangedFlag (true);
5669 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5671 notify_crosshair_change (true);
5675 /* unselect all visible objects */
5680 box
.X1
= -MAX_COORD
;
5681 box
.Y1
= -MAX_COORD
;
5684 if (SelectBlock (&box
, false))
5685 SetChangedFlag (true);
5689 /* all logical connections */
5691 if (SelectByFlag (FOUNDFLAG
, false))
5694 IncrementUndoSerialNumber ();
5695 SetChangedFlag (true);
5699 /* all physical connections */
5701 if (SelectByFlag (CONNECTEDFLAG
, false))
5704 IncrementUndoSerialNumber ();
5705 SetChangedFlag (true);
5718 /* --------------------------------------------------------------------------- */
5720 static const char saveto_syntax
[] =
5721 N_("SaveTo(Layout|LayoutAs,filename)\n"
5722 "SaveTo(AllConnections|AllUnusedPins|ElementConnections,filename)\n"
5723 "SaveTo(PasteBuffer,filename)");
5725 static const char saveto_help
[] = N_("Saves data to a file.");
5727 /* %start-doc actions SaveTo
5732 Saves the current layout.
5735 Saves the current layout, and remembers the filename used.
5737 @item AllConnections
5738 Save all connections to a file.
5741 List all unused pins to a file.
5743 @item ElementConnections
5744 Save connections to the element at the cursor to a file.
5747 Save the content of the active Buffer to a file. This is the graphical way to create a footprint.
5754 ActionSaveTo (int argc
, char **argv
, Coord x
, Coord y
)
5761 if ( ! function
|| strcasecmp (function
, "Layout") == 0)
5763 if (SavePCB (PCB
->Filename
) == 0)
5764 SetChangedFlag (false);
5773 if (strcasecmp (function
, "LayoutAs") == 0)
5775 if (SavePCB (name
) == 0)
5777 SetChangedFlag (false);
5778 free (PCB
->Filename
);
5779 PCB
->Filename
= strdup (name
);
5780 if (gui
->notify_filename_changed
!= NULL
)
5781 gui
->notify_filename_changed ();
5786 if (strcasecmp (function
, "AllConnections") == 0)
5790 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5792 LookupConnectionsToAllElements (fp
);
5794 SetChangedFlag (true);
5799 if (strcasecmp (function
, "AllUnusedPins") == 0)
5803 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5805 LookupUnusedPins (fp
);
5807 SetChangedFlag (true);
5812 if (strcasecmp (function
, "ElementConnections") == 0)
5814 ElementType
*element
;
5819 if ((SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
5820 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
5822 element
= (ElementType
*) ptrtmp
;
5824 CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5826 LookupElementConnections (element
, fp
);
5828 SetChangedFlag (true);
5834 if (strcasecmp (function
, "PasteBuffer") == 0)
5836 return SaveBufferElements (name
);
5842 /* --------------------------------------------------------------------------- */
5844 static const char savesettings_syntax
[] =
5845 N_("SaveSettings()\n"
5846 "SaveSettings(local)");
5848 static const char savesettings_help
[] = N_("Saves settings.");
5850 /* %start-doc actions SaveSettings
5852 If you pass no arguments, the settings are stored in
5853 @code{$HOME/.pcb/settings}. If you pass the word @code{local} they're
5854 saved in @code{./pcb.settings}.
5859 ActionSaveSettings (int argc
, char **argv
, Coord x
, Coord y
)
5861 int locally
= argc
> 0 ? (strncasecmp (argv
[0], "local", 5) == 0) : 0;
5862 hid_save_settings (locally
);
5866 /* --------------------------------------------------------------------------- */
5868 static const char loadfrom_syntax
[] =
5869 N_("LoadFrom(Layout|LayoutToBuffer|ElementToBuffer|Netlist|Revert,filename)");
5871 static const char loadfrom_help
[] = N_("Load layout data from a file.");
5873 /* %start-doc actions LoadFrom
5875 This action assumes you know what the filename is. The various GUIs
5876 should have a similar @code{Load} action where the filename is
5877 optional, and will provide their own file selection mechanism to let
5878 you choose the file name.
5883 Loads an entire PCB layout, replacing the current one.
5885 @item LayoutToBuffer
5886 Loads an entire PCB layout to the paste buffer.
5888 @item ElementToBuffer
5889 Loads the given element file into the paste buffer. Element files
5890 contain only a single @code{Element} definition, such as the
5891 ``newlib'' library uses.
5894 Loads a new netlist, replacing any current netlist.
5897 Re-loads the current layout from its disk file, reverting any changes
5905 ActionLoadFrom (int argc
, char **argv
, Coord x
, Coord y
)
5916 if (strcasecmp (function
, "ElementToBuffer") == 0)
5918 notify_crosshair_change (false);
5919 if (LoadElementToBuffer (PASTEBUFFER
, name
, true))
5920 SetMode (PASTEBUFFER_MODE
);
5921 notify_crosshair_change (true);
5924 else if (strcasecmp (function
, "LayoutToBuffer") == 0)
5926 notify_crosshair_change (false);
5927 if (LoadLayoutToBuffer (PASTEBUFFER
, name
))
5928 SetMode (PASTEBUFFER_MODE
);
5929 notify_crosshair_change (true);
5932 else if (strcasecmp (function
, "Layout") == 0)
5934 if (!PCB
->Changed
||
5935 gui
->confirm_dialog (_("OK to override layout data?"), 0))
5939 else if (strcasecmp (function
, "Netlist") == 0)
5941 if (PCB
->Netlistname
)
5942 free (PCB
->Netlistname
);
5943 PCB
->Netlistname
= StripWhiteSpaceAndDup (name
);
5944 FreeLibraryMemory (&PCB
->NetlistLib
);
5945 ImportNetlist (PCB
->Netlistname
);
5948 else if (strcasecmp (function
, "Revert") == 0 && PCB
->Filename
5950 || gui
->confirm_dialog (_("OK to override changes?"), 0)))
5958 /* --------------------------------------------------------------------------- */
5960 static const char new_syntax
[] = N_("New([name])");
5962 static const char new_help
[] = N_("Starts a new layout.");
5964 /* %start-doc actions New
5966 If a name is not given, one is prompted for.
5971 ActionNew (int argc
, char **argv
, Coord x
, Coord y
)
5973 char *name
= ARG (0);
5975 if (!PCB
->Changed
|| gui
->confirm_dialog (_("OK to clear layout data?"), 0))
5978 name
= strdup (name
);
5980 name
= gui
->prompt_for (_("Enter the layout name:"), "");
5985 notify_crosshair_change (false);
5986 /* do emergency saving
5987 * clear the old struct and allocate memory for the new one
5989 if (PCB
->Changed
&& Settings
.SaveInTMP
)
5993 PCB
= CreateNewPCB ();
5994 CreateNewPCBPost (PCB
, 1);
5996 /* setup the new name and reset some values to default */
6000 ResetStackAndVisibility ();
6001 SetCrosshairRange (0, 0, PCB
->MaxWidth
, PCB
->MaxHeight
);
6002 CenterDisplay (PCB
->MaxWidth
/ 2, PCB
->MaxHeight
/ 2, false);
6005 hid_action ("PCBChanged");
6006 notify_crosshair_change (true);
6013 * \brief No operation, just for testing purposes.
6014 * syntax: Bell(volume)
6017 ActionBell (char *volume
)
6022 /* --------------------------------------------------------------------------- */
6024 static const char pastebuffer_syntax
[] =
6025 N_("PasteBuffer(AddSelected|Clear|1..MAX_BUFFER)\n"
6026 "PasteBuffer(Rotate, 1..3)\n"
6027 "PasteBuffer(Convert|Save|Restore|Mirror)\n"
6028 "PasteBuffer(ToLayout, X, Y, units)");
6030 static const char pastebuffer_help
[] =
6031 N_("Various operations on the paste buffer.");
6033 /* %start-doc actions PasteBuffer
6035 There are a number of paste buffers; the actual limit is a
6036 compile-time constant @code{MAX_BUFFER} in @file{globalconst.h}. It
6037 is currently @code{5}. One of these is the ``current'' paste buffer,
6038 often referred to as ``the'' paste buffer.
6043 Copies the selected objects to the current paste buffer.
6046 Remove all objects from the current paste buffer.
6049 Convert the current paste buffer to an element. Vias are converted to
6050 pins, lines are converted to pads.
6053 Convert any elements in the paste buffer back to vias and lines.
6056 Flip all objects in the paste buffer vertically (up/down flip). To mirror
6057 horizontally, combine this with rotations.
6060 Rotates the current buffer. The number to pass is 1..3, where 1 means
6061 90 degrees counter clockwise, 2 means 180 degrees, and 3 means 90
6062 degrees clockwise (270 CCW).
6065 Saves any elements in the current buffer to the indicated file.
6068 Pastes any elements in the current buffer to the indicated X, Y
6069 coordinates in the layout. The @code{X} and @code{Y} are treated like
6070 @code{delta} is for many other objects. For each, if it's prefixed by
6071 @code{+} or @code{-}, then that amount is relative to the last
6072 location. Otherwise, it's absolute. Units can be
6073 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
6074 units, currently 1/100 mil.
6078 Selects the given buffer to be the current paste buffer.
6085 ActionPasteBuffer (int argc
, char **argv
, Coord x
, Coord y
)
6087 char *function
= argc
? argv
[0] : (char *)"";
6088 char *sbufnum
= argc
> 1 ? argv
[1] : (char *)"";
6090 static char *default_file
= NULL
;
6093 notify_crosshair_change (false);
6096 switch (GetFunctionID (function
))
6098 /* clear contents of paste buffer */
6100 ClearBuffer (PASTEBUFFER
);
6103 /* copies objects to paste buffer */
6105 AddSelectedToBuffer (PASTEBUFFER
, 0, 0, false);
6108 /* converts buffer contents into an element */
6110 ConvertBufferToElement (PASTEBUFFER
);
6113 /* break up element for editing */
6115 SmashBufferElement (PASTEBUFFER
);
6120 MirrorBuffer (PASTEBUFFER
);
6126 RotateBuffer (PASTEBUFFER
, (BYTE
) atoi (sbufnum
));
6127 SetCrosshairRangeToBuffer ();
6132 if (PASTEBUFFER
->Data
->ElementN
== 0)
6134 Message (_("Buffer has no elements!\n"));
6140 name
= gui
->fileselect (_("Save Paste Buffer As ..."),
6141 _("Choose a file to save the contents of the\n"
6142 "paste buffer to.\n"),
6143 default_file
, ".fp", "footprint",
6148 free (default_file
);
6149 default_file
= NULL
;
6153 default_file
= strdup (name
);
6164 if ((exist
= fopen (name
, "r")))
6168 confirm_dialog (_("File exists! Ok to overwrite?"), 0))
6169 SaveBufferElements (name
);
6172 SaveBufferElements (name
);
6174 if (free_name
&& name
)
6181 static Coord oldx
= 0, oldy
= 0;
6189 else if (argc
== 3 || argc
== 4)
6191 x
= GetValue (ARG (1), ARG (3), &absolute
);
6194 y
= GetValue (ARG (2), ARG (3), &absolute
);
6200 notify_crosshair_change (true);
6201 AFAIL (pastebuffer
);
6206 if (CopyPastebufferToLayout (x
, y
))
6207 SetChangedFlag (true);
6214 int number
= atoi (function
);
6216 /* correct number */
6218 SetBufferNumber (number
- 1);
6223 notify_crosshair_change (true);
6227 /* --------------------------------------------------------------------------- */
6229 static const char undo_syntax
[] = N_("Undo()\n"
6232 static const char undo_help
[] = N_("Undo recent changes.");
6234 /* %start-doc actions Undo
6236 The unlimited undo feature of @code{Pcb} allows you to recover from
6237 most operations that materially affect you work. Calling
6238 @code{Undo()} without any parameter recovers from the last (non-undo)
6239 operation. @code{ClearList} is used to release the allocated
6240 memory. @code{ClearList} is called whenever a new layout is started or
6241 loaded. See also @code{Redo} and @code{Atomic}.
6243 Note that undo groups operations by serial number; changes with the
6244 same serial number will be undone (or redone) as a group. See
6250 ActionUndo (int argc
, char **argv
, Coord x
, Coord y
)
6252 char *function
= ARG (0);
6253 if (!function
|| !*function
)
6255 /* don't allow undo in the middle of an operation */
6256 if (Settings
.Mode
!= POLYGONHOLE_MODE
&&
6257 Crosshair
.AttachedObject
.State
!= STATE_FIRST
)
6259 if (Crosshair
.AttachedBox
.State
!= STATE_FIRST
6260 && Settings
.Mode
!= ARC_MODE
)
6262 /* undo the last operation */
6264 notify_crosshair_change (false);
6265 if ((Settings
.Mode
== POLYGON_MODE
||
6266 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6267 Crosshair
.AttachedPolygon
.PointN
)
6269 GoToPreviousPoint ();
6270 notify_crosshair_change (true);
6273 /* move anchor point if undoing during line creation */
6274 if (Settings
.Mode
== LINE_MODE
)
6276 if (Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6278 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6279 Undo (true); /* undo the connection find */
6280 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
6281 SetLocalRef (0, 0, false);
6282 notify_crosshair_change (true);
6285 if (Crosshair
.AttachedLine
.State
== STATE_THIRD
)
6288 void *ptr1
, *ptr3
, *ptrtmp
;
6290 /* this search is guaranteed to succeed */
6291 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6293 Crosshair
.AttachedLine
.Point1
.X
,
6294 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6295 ptr2
= (LineType
*) ptrtmp
;
6297 /* save both ends of line */
6298 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point1
.X
;
6299 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point1
.Y
;
6300 if ((type
= Undo (true)))
6301 SetChangedFlag (true);
6302 /* check that the undo was of the right type */
6303 if ((type
& UNDO_CREATE
) == 0)
6305 /* wrong undo type, restore anchor points */
6306 Crosshair
.AttachedLine
.Point2
.X
=
6307 Crosshair
.AttachedLine
.Point1
.X
;
6308 Crosshair
.AttachedLine
.Point2
.Y
=
6309 Crosshair
.AttachedLine
.Point1
.Y
;
6310 notify_crosshair_change (true);
6313 /* move to new anchor */
6314 Crosshair
.AttachedLine
.Point1
.X
=
6315 Crosshair
.AttachedLine
.Point2
.X
;
6316 Crosshair
.AttachedLine
.Point1
.Y
=
6317 Crosshair
.AttachedLine
.Point2
.Y
;
6318 /* check if an intermediate point was removed */
6319 if (type
& UNDO_REMOVE
)
6321 /* this search should find the restored line */
6322 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6325 Crosshair
.AttachedLine
.Point2
.X
,
6326 Crosshair
.AttachedLine
.Point2
.Y
, 0);
6327 ptr2
= (LineType
*) ptrtmp
;
6328 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6330 /* undo loses CONNECTEDFLAG and FOUNDFLAG */
6331 SET_FLAG(CONNECTEDFLAG
, ptr2
);
6332 SET_FLAG(FOUNDFLAG
, ptr2
);
6333 DrawLine (CURRENT
, ptr2
);
6335 Crosshair
.AttachedLine
.Point1
.X
=
6336 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point2
.X
;
6337 Crosshair
.AttachedLine
.Point1
.Y
=
6338 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point2
.Y
;
6340 FitCrosshairIntoGrid (Crosshair
.X
, Crosshair
.Y
);
6341 AdjustAttachedObjects ();
6342 if (--addedLines
== 0)
6344 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
6345 lastLayer
= CURRENT
;
6349 /* this search is guaranteed to succeed too */
6350 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6353 Crosshair
.AttachedLine
.Point1
.X
,
6354 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6355 ptr2
= (LineType
*) ptrtmp
;
6356 lastLayer
= (LayerType
*) ptr1
;
6358 notify_crosshair_change (true);
6362 if (Settings
.Mode
== ARC_MODE
)
6364 if (Crosshair
.AttachedBox
.State
== STATE_SECOND
)
6366 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
6367 notify_crosshair_change (true);
6370 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
)
6372 void *ptr1
, *ptr2
, *ptr3
;
6374 /* guaranteed to succeed */
6375 SearchObjectByLocation (ARC_TYPE
, &ptr1
, &ptr2
, &ptr3
,
6376 Crosshair
.AttachedBox
.Point1
.X
,
6377 Crosshair
.AttachedBox
.Point1
.Y
, 0);
6378 bx
= GetArcEnds ((ArcType
*) ptr2
);
6379 Crosshair
.AttachedBox
.Point1
.X
=
6380 Crosshair
.AttachedBox
.Point2
.X
= bx
->X1
;
6381 Crosshair
.AttachedBox
.Point1
.Y
=
6382 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y1
;
6383 AdjustAttachedObjects ();
6384 if (--addedLines
== 0)
6385 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
6388 /* undo the last destructive operation */
6390 SetChangedFlag (true);
6394 switch (GetFunctionID (function
))
6396 /* clear 'undo objects' list */
6398 ClearUndoList (false);
6402 notify_crosshair_change (true);
6406 /* --------------------------------------------------------------------------- */
6408 static const char redo_syntax
[] = N_("Redo()");
6410 static const char redo_help
[] = N_("Redo recent \"undo\" operations.");
6412 /* %start-doc actions Redo
6414 This routine allows you to recover from the last undo command. You
6415 might want to do this if you thought that undo was going to revert
6416 something other than what it actually did (in case you are confused
6417 about which operations are un-doable), or if you have been backing up
6418 through a long undo list and over-shoot your stopping point. Any
6419 change that is made since the undo in question will trim the redo
6420 list. For example if you add ten lines, then undo three of them you
6421 could use redo to put them back, but if you move a line on the board
6422 before performing the redo, you will lose the ability to "redo" the
6423 three "undone" lines.
6428 ActionRedo (int argc
, char **argv
, Coord x
, Coord y
)
6430 if (((Settings
.Mode
== POLYGON_MODE
||
6431 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6432 Crosshair
.AttachedPolygon
.PointN
) ||
6433 Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6435 notify_crosshair_change (false);
6438 SetChangedFlag (true);
6439 if (Settings
.Mode
== LINE_MODE
&&
6440 Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
6442 LineType
*line
= g_list_last (CURRENT
->Line
)->data
;
6443 Crosshair
.AttachedLine
.Point1
.X
=
6444 Crosshair
.AttachedLine
.Point2
.X
= line
->Point2
.X
;
6445 Crosshair
.AttachedLine
.Point1
.Y
=
6446 Crosshair
.AttachedLine
.Point2
.Y
= line
->Point2
.Y
;
6450 notify_crosshair_change (true);
6454 /* --------------------------------------------------------------------------- */
6456 static const char polygon_syntax
[] = N_("Polygon(Close|PreviousPoint)");
6458 static const char polygon_help
[] = N_("Some polygon related stuff.");
6460 /* %start-doc actions Polygon
6462 Polygons need a special action routine to make life easier.
6467 Creates the final segment of the polygon. This may fail if clipping
6468 to 45 degree lines is switched on, in which case a warning is issued.
6471 Resets the newly entered corner to the previous one. The Undo action
6472 will call Polygon(PreviousPoint) when appropriate to do so.
6479 ActionPolygon (int argc
, char **argv
, Coord x
, Coord y
)
6481 char *function
= ARG (0);
6482 if (function
&& Settings
.Mode
== POLYGON_MODE
)
6484 notify_crosshair_change (false);
6485 switch (GetFunctionID (function
))
6487 /* close open polygon if possible */
6492 /* go back to the previous point */
6493 case F_PreviousPoint
:
6494 GoToPreviousPoint ();
6497 notify_crosshair_change (true);
6502 /* --------------------------------------------------------------------------- */
6504 static const char routestyle_syntax
[] = N_("RouteStyle(1|2|3|4)");
6506 static const char routestyle_help
[] =
6507 N_("Copies the indicated routing style into the current sizes.");
6509 /* %start-doc actions RouteStyle
6514 ActionRouteStyle (int argc
, char **argv
, Coord x
, Coord y
)
6516 char *str
= ARG (0);
6517 RouteStyleType
*rts
;
6522 number
= atoi (str
);
6523 if (number
> 0 && number
<= NUM_STYLES
)
6525 rts
= &PCB
->RouteStyle
[number
- 1];
6526 SetLineSize (rts
->Thick
);
6527 SetViaSize (rts
->Diameter
, true);
6528 SetViaDrillingHole (rts
->Hole
, true);
6529 SetKeepawayWidth (rts
->Keepaway
);
6530 hid_action("RouteStylesChanged");
6537 /* --------------------------------------------------------------------------- */
6539 static const char moveobject_syntax
[] = N_("MoveObject(X,Y,dim)");
6541 static const char moveobject_help
[] =
6542 N_("Moves the object under the crosshair.");
6544 /* %start-doc actions MoveObject
6546 The @code{X} and @code{Y} are treated like @code{delta} is for many
6547 other objects. For each, if it's prefixed by @code{+} or @code{-},
6548 then that amount is relative. Otherwise, it's absolute. Units can be
6549 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
6550 units, currently 1/100 mil.
6555 ActionMoveObject (int argc
, char **argv
, Coord x
, Coord y
)
6557 char *x_str
= ARG (0);
6558 char *y_str
= ARG (1);
6559 char *units
= ARG (2);
6561 bool absolute1
, absolute2
;
6562 void *ptr1
, *ptr2
, *ptr3
;
6565 ny
= GetValue (y_str
, units
, &absolute1
);
6566 nx
= GetValue (x_str
, units
, &absolute2
);
6568 type
= SearchScreen (x
, y
, MOVE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6569 if (type
== NO_TYPE
)
6571 Message (_("Nothing found under crosshair\n"));
6578 Crosshair
.AttachedObject
.RubberbandN
= 0;
6579 if (TEST_FLAG (RUBBERBANDFLAG
, PCB
))
6580 LookupRubberbandLines (type
, ptr1
, ptr2
, ptr3
);
6581 if (type
== ELEMENT_TYPE
)
6582 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
6583 MoveObjectAndRubberband (type
, ptr1
, ptr2
, ptr3
, nx
, ny
);
6584 SetChangedFlag (true);
6588 /* --------------------------------------------------------------------------- */
6590 static const char movetocurrentlayer_syntax
[] =
6591 N_("MoveToCurrentLayer(Object|SelectedObjects)");
6593 static const char movetocurrentlayer_help
[] =
6594 N_("Moves objects to the current layer.");
6596 /* %start-doc actions MoveToCurrentLayer
6598 Note that moving an element from a component layer to a solder layer,
6599 or from solder to component, won't automatically flip it. Use the
6600 @code{Flip()} action to do that.
6605 ActionMoveToCurrentLayer (int argc
, char **argv
, Coord x
, Coord y
)
6607 char *function
= ARG (0);
6610 switch (GetFunctionID (function
))
6615 void *ptr1
, *ptr2
, *ptr3
;
6617 gui
->get_coords (_("Select an Object"), &x
, &y
);
6619 SearchScreen (x
, y
, MOVETOLAYER_TYPES
,
6620 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6621 if (MoveObjectToLayer (type
, ptr1
, ptr2
, ptr3
, CURRENT
, false))
6622 SetChangedFlag (true);
6626 case F_SelectedObjects
:
6628 if (MoveSelectedObjectsToLayer (CURRENT
))
6629 SetChangedFlag (true);
6637 static const char setsame_syntax
[] = N_("SetSame()");
6639 static const char setsame_help
[] =
6640 N_("Sets current layer and sizes to match indicated item.");
6642 /* %start-doc actions SetSame
6644 When invoked over any line, arc, polygon, or via, this changes the
6645 current layer to be the layer that item is on, and changes the current
6646 sizes (thickness, keepaway, drill, etc) according to that item.
6651 ActionSetSame (int argc
, char **argv
, Coord x
, Coord y
)
6653 void *ptr1
, *ptr2
, *ptr3
;
6655 LayerType
*layer
= CURRENT
;
6657 type
= SearchScreen (x
, y
, CLONE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6658 /* set layer current and size from line or arc */
6662 notify_crosshair_change (false);
6663 Settings
.LineThickness
= ((LineType
*) ptr2
)->Thickness
;
6664 Settings
.Keepaway
= ((LineType
*) ptr2
)->Clearance
/ 2;
6665 layer
= (LayerType
*) ptr1
;
6666 if (Settings
.Mode
!= LINE_MODE
)
6667 SetMode (LINE_MODE
);
6668 notify_crosshair_change (true);
6669 hid_action ("RouteStylesChanged");
6673 notify_crosshair_change (false);
6674 Settings
.LineThickness
= ((ArcType
*) ptr2
)->Thickness
;
6675 Settings
.Keepaway
= ((ArcType
*) ptr2
)->Clearance
/ 2;
6676 layer
= (LayerType
*) ptr1
;
6677 if (Settings
.Mode
!= ARC_MODE
)
6679 notify_crosshair_change (true);
6680 hid_action ("RouteStylesChanged");
6684 layer
= (LayerType
*) ptr1
;
6688 notify_crosshair_change (false);
6689 Settings
.ViaThickness
= ((PinType
*) ptr2
)->Thickness
;
6690 Settings
.ViaDrillingHole
= ((PinType
*) ptr2
)->DrillingHole
;
6691 Settings
.Keepaway
= ((PinType
*) ptr2
)->Clearance
/ 2;
6692 if (Settings
.Mode
!= VIA_MODE
)
6694 notify_crosshair_change (true);
6695 hid_action ("RouteStylesChanged");
6701 if (layer
!= CURRENT
)
6703 ChangeGroupVisibility (GetLayerNumber (PCB
->Data
, layer
), true, true);
6710 /* --------------------------------------------------------------------------- */
6712 static const char setflag_syntax
[] =
6713 N_("SetFlag(Object|Selected|SelectedObjects, flag)\n"
6714 "SetFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6715 "SetFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6716 "SetFlag(SelectedElements, flag)\n"
6717 "flag = square | octagon | thermal | join");
6719 static const char setflag_help
[] = N_("Sets flags on objects.");
6721 /* %start-doc actions SetFlag
6723 Turns the given flag on, regardless of its previous setting. See
6727 SetFlag(SelectedPins,thermal)
6733 ActionSetFlag (int argc
, char **argv
, Coord x
, Coord y
)
6735 char *function
= ARG (0);
6736 char *flag
= ARG (1);
6737 ChangeFlag (function
, flag
, 1, "SetFlag");
6741 /* --------------------------------------------------------------------------- */
6743 static const char clrflag_syntax
[] =
6744 N_("ClrFlag(Object|Selected|SelectedObjects, flag)\n"
6745 "ClrFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6746 "ClrFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6747 "ClrFlag(SelectedElements, flag)\n"
6748 "flag = square | octagon | thermal | join");
6750 static const char clrflag_help
[] = N_("Clears flags on objects.");
6752 /* %start-doc actions ClrFlag
6754 Turns the given flag off, regardless of its previous setting. See
6758 ClrFlag(SelectedLines,join)
6764 ActionClrFlag (int argc
, char **argv
, Coord x
, Coord y
)
6766 char *function
= ARG (0);
6767 char *flag
= ARG (1);
6768 ChangeFlag (function
, flag
, 0, "ClrFlag");
6772 /* --------------------------------------------------------------------------- */
6774 static const char changeflag_syntax
[] =
6775 N_("ChangeFlag(Object|Selected|SelectedObjects, flag, value)\n"
6776 "ChangeFlag(SelectedLines|SelectedPins|SelectedVias, flag, value)\n"
6777 "ChangeFlag(SelectedPads|SelectedTexts|SelectedNames, flag, value)\n"
6778 "ChangeFlag(SelectedElements, flag, value)\n"
6779 "flag = square | octagon | thermal | join\n"
6782 static const char changeflag_help
[] = N_("Sets or clears flags on objects.");
6784 /* %start-doc actions ChangeFlag
6786 Toggles the given flag on the indicated object(s). The flag may be
6787 one of the flags listed above (square, octagon, thermal, join). The
6788 value may be the number 0 or 1. If the value is 0, the flag is
6789 cleared. If the value is 1, the flag is set.
6794 ActionChangeFlag (int argc
, char **argv
, Coord x
, Coord y
)
6796 char *function
= ARG (0);
6797 char *flag
= ARG (1);
6798 int value
= argc
> 2 ? atoi (argv
[2]) : -1;
6799 if (value
!= 0 && value
!= 1)
6802 ChangeFlag (function
, flag
, value
, "ChangeFlag");
6808 ChangeFlag (char *what
, char *flag_name
, int value
, char *cmd_name
)
6810 bool (*set_object
) (int, void *, void *, void *);
6811 bool (*set_selected
) (int);
6813 if (NSTRCMP (flag_name
, "square") == 0)
6815 set_object
= value
? SetObjectSquare
: ClrObjectSquare
;
6816 set_selected
= value
? SetSelectedSquare
: ClrSelectedSquare
;
6818 else if (NSTRCMP (flag_name
, "octagon") == 0)
6820 set_object
= value
? SetObjectOctagon
: ClrObjectOctagon
;
6821 set_selected
= value
? SetSelectedOctagon
: ClrSelectedOctagon
;
6823 else if (NSTRCMP (flag_name
, "join") == 0)
6825 /* Note: these are backwards, because the flag is "clear" but
6826 the command is "join". */
6827 set_object
= value
? ClrObjectJoin
: SetObjectJoin
;
6828 set_selected
= value
? ClrSelectedJoin
: SetSelectedJoin
;
6832 Message (_("%s(): Flag \"%s\" is not valid\n"), cmd_name
, flag_name
);
6836 switch (GetFunctionID (what
))
6841 void *ptr1
, *ptr2
, *ptr3
;
6844 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
6845 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6846 if (TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
6847 Message (_("Sorry, the object is locked\n"));
6848 if (set_object (type
, ptr1
, ptr2
, ptr3
))
6849 SetChangedFlag (true);
6853 case F_SelectedVias
:
6854 if (set_selected (VIA_TYPE
))
6855 SetChangedFlag (true);
6858 case F_SelectedPins
:
6859 if (set_selected (PIN_TYPE
))
6860 SetChangedFlag (true);
6863 case F_SelectedPads
:
6864 if (set_selected (PAD_TYPE
))
6865 SetChangedFlag (true);
6868 case F_SelectedLines
:
6869 if (set_selected (LINE_TYPE
))
6870 SetChangedFlag (true);
6873 case F_SelectedTexts
:
6874 if (set_selected (TEXT_TYPE
))
6875 SetChangedFlag (true);
6878 case F_SelectedNames
:
6879 if (set_selected (ELEMENTNAME_TYPE
))
6880 SetChangedFlag (true);
6883 case F_SelectedElements
:
6884 if (set_selected (ELEMENT_TYPE
))
6885 SetChangedFlag (true);
6889 case F_SelectedObjects
:
6890 if (set_selected (CHANGESIZE_TYPES
))
6891 SetChangedFlag (true);
6896 /* --------------------------------------------------------------------------- */
6898 static const char executefile_syntax
[] = N_("ExecuteFile(filename)");
6900 static const char executefile_help
[] = N_("Run actions from the given file.");
6902 /* %start-doc actions ExecuteFile
6904 Lines starting with @code{#} are ignored.
6909 ActionExecuteFile (int argc
, char **argv
, Coord x
, Coord y
)
6918 AFAIL (executefile
);
6922 if ((fp
= fopen (fname
, "r")) == NULL
)
6924 fprintf (stderr
, _("Could not open actions file \"%s\".\n"), fname
);
6929 defer_needs_update
= 0;
6930 while (fgets (line
, sizeof (line
), fp
) != NULL
)
6935 /* eat the trailing newline */
6936 while (*sp
&& *sp
!= '\r' && *sp
!= '\n')
6940 /* eat leading spaces and tabs */
6942 while (*sp
&& (*sp
== ' ' || *sp
== '\t'))
6946 * if we have anything left and its not a comment line
6950 if (*sp
&& *sp
!= '#')
6952 /*Message ("%s : line %-3d : \"%s\"\n", fname, n, sp);*/
6953 hid_parse_actions (sp
);
6958 if (defer_needs_update
)
6960 IncrementUndoSerialNumber ();
6961 gui
->invalidate_all ();
6967 /* --------------------------------------------------------------------------- */
6970 ActionPSCalib (int argc
, char **argv
, Coord x
, Coord y
)
6972 HID
*ps
= hid_find_exporter ("ps");
6973 ps
->calibrate (0.0,0.0);
6977 /* --------------------------------------------------------------------------- */
6979 static ElementType
*element_cache
= NULL
;
6981 static ElementType
*
6982 find_element_by_refdes (char *refdes
)
6985 && NAMEONPCB_NAME(element_cache
)
6986 && strcmp (NAMEONPCB_NAME(element_cache
), refdes
) == 0)
6987 return element_cache
;
6989 ELEMENT_LOOP (PCB
->Data
);
6991 if (NAMEONPCB_NAME(element
)
6992 && strcmp (NAMEONPCB_NAME(element
), refdes
) == 0)
6994 element_cache
= element
;
6995 return element_cache
;
7002 static AttributeType
*
7003 lookup_attr (AttributeListType
*list
, const char *name
)
7006 for (i
=0; i
<list
->Number
; i
++)
7007 if (strcmp (list
->List
[i
].name
, name
) == 0)
7008 return & list
->List
[i
];
7013 delete_attr (AttributeListType
*list
, AttributeType
*attr
)
7015 int idx
= attr
- list
->List
;
7016 if (idx
< 0 || idx
>= list
->Number
)
7018 if (list
->Number
- idx
> 1)
7019 memmove (attr
, attr
+1, (list
->Number
- idx
- 1) * sizeof(AttributeType
));
7023 /* ---------------------------------------------------------------- */
7024 static const char elementlist_syntax
[] =
7025 N_("ElementList(Start|Done|Need,<refdes>,<footprint>,<value>)");
7027 static const char elementlist_help
[] =
7028 N_("Adds the given element if it doesn't already exist.");
7030 /* %start-doc actions elementlist
7035 Indicates the start of an element list; call this before any Need
7039 Searches the board for an element with a matching refdes.
7041 If found, the value and footprint are updated.
7043 If not found, a new element is created with the given footprint and value.
7046 Compares the list of elements needed since the most recent
7047 @code{start} with the list of elements actually on the board. Any
7048 elements that weren't listed are selected, so that the user may delete
7055 static int number_of_footprints_not_found
;
7058 parse_layout_attribute_units (char *name
, int def
)
7060 const char *as
= AttributeGet (PCB
, name
);
7063 return GetValue (as
, NULL
, NULL
);
7067 ActionElementList (int argc
, char **argv
, Coord x
, Coord y
)
7069 ElementType
*e
= NULL
;
7070 char *refdes
, *value
, *footprint
, *old
;
7075 AFAIL (elementlist
);
7080 printf("Entered ActionElementList, executing function %s\n", function
);
7083 if (strcasecmp (function
, "start") == 0)
7085 ELEMENT_LOOP (PCB
->Data
);
7087 CLEAR_FLAG (FOUNDFLAG
, element
);
7090 element_cache
= NULL
;
7091 number_of_footprints_not_found
= 0;
7095 if (strcasecmp (function
, "done") == 0)
7097 ELEMENT_LOOP (PCB
->Data
);
7099 if (TEST_FLAG (FOUNDFLAG
, element
))
7101 CLEAR_FLAG (FOUNDFLAG
, element
);
7103 else if (! EMPTY_STRING_P (NAMEONPCB_NAME (element
)))
7105 /* Unnamed elements should remain untouched */
7106 SET_FLAG (SELECTEDFLAG
, element
);
7110 if (number_of_footprints_not_found
> 0)
7111 gui
->confirm_dialog (_("Not all requested footprints were found.\n"
7112 "See the message log for details"),
7117 if (strcasecmp (function
, "need") != 0)
7118 AFAIL (elementlist
);
7121 AFAIL (elementlist
);
7130 args
[0] = footprint
;
7135 printf(" ... footprint = %s\n", footprint
);
7136 printf(" ... refdes = %s\n", refdes
);
7137 printf(" ... value = %s\n", value
);
7140 e
= find_element_by_refdes (refdes
);
7147 printf(" ... Footprint not on board, need to add it.\n");
7149 /* Not on board, need to add it. */
7150 if (LoadFootprint(argc
, args
, x
, y
))
7152 number_of_footprints_not_found
++;
7156 nx
= PCB
->MaxWidth
/ 2;
7157 ny
= PCB
->MaxHeight
/ 2;
7158 d
= MIN (PCB
->MaxWidth
, PCB
->MaxHeight
) / 10;
7160 nx
= parse_layout_attribute_units ("import::newX", nx
);
7161 ny
= parse_layout_attribute_units ("import::newY", ny
);
7162 d
= parse_layout_attribute_units ("import::disperse", d
);
7166 nx
+= rand () % (d
*2) - d
;
7167 ny
+= rand () % (d
*2) - d
;
7172 if (nx
>= PCB
->MaxWidth
)
7173 nx
= PCB
->MaxWidth
- 1;
7176 if (ny
>= PCB
->MaxHeight
)
7177 ny
= PCB
->MaxHeight
- 1;
7179 /* Place components onto center of board. */
7180 if (CopyPastebufferToLayout (nx
, ny
))
7181 SetChangedFlag (true);
7184 else if (e
&& DESCRIPTION_NAME(e
) && strcmp (DESCRIPTION_NAME(e
), footprint
) != 0)
7187 printf(" ... Footprint on board, but different from footprint loaded.\n");
7193 /* Different footprint, we need to swap them out. */
7194 if (LoadFootprint(argc
, args
, x
, y
))
7196 number_of_footprints_not_found
++;
7200 er
= ElementOrientation (e
);
7201 pe
= PASTEBUFFER
->Data
->Element
->data
;
7203 MirrorElementCoordinates (PASTEBUFFER
->Data
, pe
, pe
->MarkY
*2 - PCB
->MaxHeight
);
7204 pr
= ElementOrientation (pe
);
7210 RotateElementLowLevel (PASTEBUFFER
->Data
, pe
, pe
->MarkX
, pe
->MarkY
, (er
-pr
+4)%4);
7212 for (i
=0; i
<MAX_ELEMENTNAMES
; i
++)
7214 pe
->Name
[i
].X
= e
->Name
[i
].X
- mx
+ pe
->MarkX
;
7215 pe
->Name
[i
].Y
= e
->Name
[i
].Y
- my
+ pe
->MarkY
;
7216 pe
->Name
[i
].Direction
= e
->Name
[i
].Direction
;
7217 pe
->Name
[i
].Scale
= e
->Name
[i
].Scale
;
7222 if (CopyPastebufferToLayout (mx
, my
))
7223 SetChangedFlag (true);
7226 /* Now reload footprint */
7227 element_cache
= NULL
;
7228 e
= find_element_by_refdes (refdes
);
7230 old
= ChangeElementText (PCB
, PCB
->Data
, e
, NAMEONPCB_INDEX
, strdup (refdes
));
7233 old
= ChangeElementText (PCB
, PCB
->Data
, e
, VALUE_INDEX
, strdup (value
));
7237 SET_FLAG (FOUNDFLAG
, e
);
7240 printf(" ... Leaving ActionElementList.\n");
7246 /* ---------------------------------------------------------------- */
7247 static const char elementsetattr_syntax
[] =
7248 N_("ElementSetAttr(refdes,name[,value])");
7250 static const char elementsetattr_help
[] =
7251 N_("Sets or clears an element-specific attribute.");
7253 /* %start-doc actions elementsetattr
7255 If a value is specified, the named attribute is added (if not already
7256 present) or changed (if it is) to the given value. If the value is
7257 not specified, the given attribute is removed if present.
7262 ActionElementSetAttr (int argc
, char **argv
, Coord x
, Coord y
)
7264 ElementType
*e
= NULL
;
7265 char *refdes
, *name
, *value
;
7266 AttributeType
*attr
;
7270 AFAIL (elementsetattr
);
7277 ELEMENT_LOOP (PCB
->Data
);
7279 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
7289 Message(_("Cannot change attribute of %s - element not found\n"), refdes
);
7293 attr
= lookup_attr (&e
->Attributes
, name
);
7298 attr
->value
= strdup (value
);
7300 if (attr
&& ! value
)
7302 delete_attr (& e
->Attributes
, attr
);
7306 CreateNewAttribute (& e
->Attributes
, name
, value
);
7312 /* ---------------------------------------------------------------- */
7313 static const char execcommand_syntax
[] = N_("ExecCommand(command)");
7315 static const char execcommand_help
[] = N_("Runs a command.");
7317 /* %start-doc actions execcommand
7319 Runs the given command, which is a system executable.
7324 ActionExecCommand (int argc
, char **argv
, Coord x
, Coord y
)
7330 AFAIL (execcommand
);
7335 if (system (command
))
7340 /* ---------------------------------------------------------------- */
7343 pcb_spawnvp (char **argv
)
7345 #ifdef HAVE__SPAWNVP
7346 int result
= _spawnvp (_P_WAIT
, argv
[0], (const char * const *) argv
);
7357 Message(_("Cannot fork!"));
7363 execvp (argv
[0], argv
);
7376 /* ---------------------------------------------------------------- */
7379 * \brief Creates a new temporary file name.
7381 * Hopefully the operating system provides a mkdtemp() function to
7382 * securily create a temporary directory with mode 0700.\n
7383 * If so then that directory is created and the returned string is made
7384 * up of the directory plus the name variable.\n
7387 * tempfile_name_new ("myfile") might return
7388 * "/var/tmp/pcb.123456/myfile".
7390 * If mkdtemp() is not available then 'name' is ignored and the
7391 * insecure tmpnam() function is used.
7393 * Files/names created with tempfile_name_new() should be unlinked
7394 * with tempfile_unlink to make sure the temporary directory is also
7395 * removed when mkdtemp() is used.
7398 tempfile_name_new (char * name
)
7400 char *tmpfile
= NULL
;
7402 char *tmpdir
, *mytmpdir
;
7406 assert ( name
!= NULL
);
7409 #define TEMPLATE "pcb.XXXXXXXX"
7412 tmpdir
= getenv ("TMPDIR");
7414 /* FIXME -- what about win32? */
7415 if (tmpdir
== NULL
) {
7419 mytmpdir
= (char *) malloc (sizeof(char) *
7424 if (mytmpdir
== NULL
) {
7425 fprintf (stderr
, "%s(): malloc failed()\n", __FUNCTION__
);
7430 (void)strcat (mytmpdir
, tmpdir
);
7431 (void)strcat (mytmpdir
, PCB_DIR_SEPARATOR_S
);
7432 (void)strcat (mytmpdir
, TEMPLATE
);
7433 if (mkdtemp (mytmpdir
) == NULL
) {
7434 fprintf (stderr
, "%s(): mkdtemp (\"%s\") failed\n", __FUNCTION__
, mytmpdir
);
7440 len
= strlen (mytmpdir
) + /* the temp directory name */
7441 1 + /* the directory sep. */
7442 strlen (name
) + /* the file name */
7443 1 /* the \0 termination */
7446 tmpfile
= (char *) malloc (sizeof (char) * len
);
7449 (void)strcat (tmpfile
, mytmpdir
);
7450 (void)strcat (tmpfile
, PCB_DIR_SEPARATOR_S
);
7451 (void)strcat (tmpfile
, name
);
7457 * tmpnam() uses a static buffer so strdup() the result right away
7458 * in case someone decides to create multiple temp names.
7460 tmpfile
= strdup (tmpnam (NULL
));
7463 /* Guile doesn't like \ separators */
7465 for (c
= tmpfile
; *c
; c
++)
7475 /* ---------------------------------------------------------------- */
7478 * \brief Unlink a temporary file.
7480 * If we have mkdtemp() then our temp file lives in a temporary
7481 * directory and we need to remove that directory too.
7484 tempfile_unlink (char * name
)
7487 /* SDB says: Want to keep old temp files for examiniation when debugging */
7496 /* it is possible that the file was never created so it is OK if the
7499 /* now figure out the directory name to remove */
7500 e
= strlen (name
) - 1;
7501 while (e
> 0 && name
[e
] != PCB_DIR_SEPARATOR_C
) {e
--;}
7503 dname
= strdup (name
);
7507 * at this point, e *should* point to the end of the directory part
7508 * but lets make sure.
7511 rc2
= rmdir (dname
);
7517 fprintf (stderr
, _("%s(): Unable to determine temp directory name from the temp file\n"),
7519 fprintf (stderr
, "%s(): \"%s\"\n",
7520 __FUNCTION__
, name
);
7524 /* name was allocated with malloc */
7529 * FIXME - should also return -1 if the temp file exists and was not
7537 int rc
= unlink (name
);
7540 fprintf (stderr
, _("Failed to unlink \"%s\"\n"), name
);
7551 /* ---------------------------------------------------------------- */
7552 static const char import_syntax
[] =
7554 "Import([gnetlist|make[,source,source,...]])\n"
7555 "Import(setnewpoint[,(mark|center|X,Y)])\n"
7556 "Import(setdisperse,D,units)\n");
7558 static const char import_help
[] = N_("Import schematics.");
7560 /* %start-doc actions Import
7562 Imports element and netlist data from the schematics (or some other
7563 source). The first parameter, which is optional, is the mode. If not
7564 specified, the @code{import::mode} attribute in the PCB is used.
7565 @code{gnetlist} means gnetlist is used to obtain the information from
7566 the schematics. @code{make} invokes @code{make}, assuming the user
7567 has a @code{Makefile} in the current directory. The @code{Makefile}
7568 will be invoked with the following variables set:
7573 The name of the .pcb file
7576 A space-separated list of source files
7579 The name of the file in which to put the command script, which may
7580 contain any @pcb{} actions. By default, this is a temporary file
7581 selected by @pcb{}, but if you specify an @code{import::outfile}
7582 attribute, that file name is used instead (and not automatically
7583 deleted afterwards).
7587 The target specified to be built is the first of these that apply:
7592 The target specified by an @code{import::target} attribute.
7595 The output file specified by an @code{import::outfile} attribute.
7598 If nothing else is specified, the target is @code{pcb_import}.
7602 If you specify an @code{import::makefile} attribute, then "-f <that
7603 file>" will be added to the command line.
7605 If you specify the mode, you may also specify the source files
7606 (schematics). If you do not specify any, the list of schematics is
7607 obtained by reading the @code{import::src@var{N}} attributes (like
7608 @code{import::src0}, @code{import::src1}, etc).
7610 For compatibility with future extensions to the import file format,
7611 the generated file @emph{must not} start with the two characters
7614 If a temporary file is needed the @code{TMPDIR} environment variable
7615 is used to select its location.
7617 Note that the programs @code{gnetlist} and @code{make} may be
7618 overridden by the user via the @code{make-program} and @code{gnetlist}
7619 @code{pcb} settings (i.e. in @code{~/.pcb/settings} or on the command
7622 If @pcb{} cannot determine which schematic(s) to import from, the GUI
7623 is called to let user choose (see @code{ImportGUI()}).
7625 Note that Import() doesn't delete anything - after an Import, elements
7626 which shouldn't be on the board are selected and may be removed once
7627 it's determined that the deletion is appropriate.
7629 If @code{Import()} is called with @code{setnewpoint}, then the location
7630 of new components can be specified. This is where parts show up when
7631 they're added to the board. The default is the center of the board.
7635 @item Import(setnewpoint)
7637 Prompts the user to click on the board somewhere, uses that point. If
7638 called by a hotkey, uses the current location of the crosshair.
7640 @item Import(setnewpoint,mark)
7642 Uses the location of the mark. If no mark is present, the point is
7645 @item Import(setnewpoint,center)
7647 Resets the point to the center of the board.
7649 @item Import(setnewpoint,X,Y,units)
7651 Sets the point to the specific coordinates given. Example:
7652 @code{Import(setnewpoint,50,25,mm)}
7656 Note that the X and Y locations are stored in attributes named
7657 @code{import::newX} and @code{import::newY} so you could change them
7658 manually if you wished.
7660 Calling @code{Import(setdisperse,D,units)} sets how much the newly
7661 placed elements are dispersed relative to the set point. For example,
7662 @code{Import(setdisperse,10,mm)} will offset each part randomly up to
7663 10mm away from the point. The default dispersion is 1/10th of the
7664 smallest board dimension. Dispersion is saved in the
7665 @code{import::disperse} attribute.
7670 ActionImport (int argc
, char **argv
, Coord x
, Coord y
)
7673 char **sources
= NULL
;
7677 printf("ActionImport: =========== Entering ActionImport ============\n");
7682 if (mode
&& strcasecmp (mode
, "setdisperse") == 0)
7691 const char *as
= AttributeGet (PCB
, "import::disperse");
7692 ds
= gui
->prompt_for(_("Enter dispersion:"), as
? as
: "0");
7696 sprintf(buf
, "%s%s", ds
, units
);
7697 AttributePut (PCB
, "import::disperse", buf
);
7700 AttributePut (PCB
, "import::disperse", ds
);
7701 if (ARG (1) == NULL
)
7706 if (mode
&& strcasecmp (mode
, "setnewpoint") == 0)
7708 const char *xs
, *ys
, *units
;
7718 gui
->get_coords (_("Click on a location"), &x
, &y
);
7720 else if (strcasecmp (xs
, "center") == 0)
7722 AttributeRemove (PCB
, "import::newX");
7723 AttributeRemove (PCB
, "import::newY");
7726 else if (strcasecmp (xs
, "mark") == 0)
7736 x
= GetValue (xs
, units
, NULL
);
7737 y
= GetValue (ys
, units
, NULL
);
7741 Message (_("Bad syntax for Import(setnewpoint)"));
7745 pcb_snprintf (buf
, sizeof (buf
), "%$ms", x
);
7746 AttributePut (PCB
, "import::newX", buf
);
7747 pcb_snprintf (buf
, sizeof (buf
), "%$ms", y
);
7748 AttributePut (PCB
, "import::newY", buf
);
7753 mode
= AttributeGet (PCB
, "import::mode");
7760 nsources
= argc
- 1;
7771 sprintf(sname
, "import::src%d", nsources
);
7772 src
= AttributeGet (PCB
, sname
);
7777 sources
= (char **) malloc ((nsources
+ 1) * sizeof (char *));
7781 sprintf(sname
, "import::src%d", nsources
);
7782 src
= AttributeGet (PCB
, sname
);
7783 sources
[nsources
] = src
;
7790 /* Replace .pcb with .sch and hope for the best. */
7791 char *pcbname
= PCB
->Filename
;
7793 char *dot
, *slash
, *bslash
;
7796 return hid_action("ImportGUI");
7798 schname
= (char *) malloc (strlen(pcbname
) + 5);
7799 strcpy (schname
, pcbname
);
7800 dot
= strchr (schname
, '.');
7801 slash
= strchr (schname
, '/');
7802 bslash
= strchr (schname
, '\\');
7803 if (dot
&& slash
&& dot
< slash
)
7805 if (dot
&& bslash
&& dot
< bslash
)
7809 strcat (schname
, ".sch");
7811 if (access (schname
, F_OK
))
7814 return hid_action("ImportGUI");
7817 sources
= (char **) malloc (2 * sizeof (char *));
7818 sources
[0] = schname
;
7823 if (strcasecmp (mode
, "gnetlist") == 0)
7825 char *tmpfile
= tempfile_name_new ("gnetlist_output");
7829 if (tmpfile
== NULL
) {
7830 Message (_("Could not create temp file"));
7834 cmd
= (char **) malloc ((7 + nsources
) * sizeof (char *));
7835 cmd
[0] = Settings
.GnetlistProgram
;
7841 for (i
=0; i
<nsources
; i
++)
7842 cmd
[6+i
] = sources
[i
];
7843 cmd
[6+nsources
] = NULL
;
7846 printf("ActionImport: =========== About to run gnetlist ============\n");
7847 printf("%s %s %s %s %s %s %s ...\n",
7848 cmd
[0], cmd
[1], cmd
[2], cmd
[3], cmd
[4], cmd
[5], cmd
[6]);
7851 if (pcb_spawnvp (cmd
))
7858 printf("ActionImport: =========== About to run ActionExecuteFile, file = %s ============\n", tmpfile
);
7863 ActionExecuteFile (1, cmd
, 0, 0);
7866 tempfile_unlink (tmpfile
);
7868 else if (strcasecmp (mode
, "make") == 0)
7870 int must_free_tmpfile
= 0;
7876 char *user_outfile
= NULL
;
7877 char *user_makefile
= NULL
;
7878 char *user_target
= NULL
;
7881 user_outfile
= AttributeGet (PCB
, "import::outfile");
7882 user_makefile
= AttributeGet (PCB
, "import::makefile");
7883 user_target
= AttributeGet (PCB
, "import::target");
7884 if (user_outfile
&& !user_target
)
7885 user_target
= user_outfile
;
7888 tmpfile
= user_outfile
;
7891 tmpfile
= tempfile_name_new ("gnetlist_output");
7892 if (tmpfile
== NULL
) {
7893 Message (_("Could not create temp file"));
7897 must_free_tmpfile
= 1;
7900 srclen
= sizeof("SRCLIST=") + 2;
7901 for (i
=0; i
<nsources
; i
++)
7902 srclen
+= strlen (sources
[i
]) + 2;
7903 srclist
= (char *) malloc (srclen
);
7904 strcpy (srclist
, "SRCLIST=");
7905 for (i
=0; i
<nsources
; i
++)
7908 strcat (srclist
, " ");
7909 strcat (srclist
, sources
[i
]);
7912 cmd
[0] = Settings
.MakeProgram
;
7914 cmd
[2] = Concat ("PCB=", PCB
->Filename
, NULL
);
7916 cmd
[4] = Concat ("OUT=", tmpfile
, NULL
);
7921 cmd
[i
++] = user_makefile
;
7923 cmd
[i
++] = user_target
? user_target
: (char *)"pcb_import";
7926 if (pcb_spawnvp (cmd
))
7928 if (must_free_tmpfile
)
7938 ActionExecuteFile (1, cmd
, 0, 0);
7943 if (must_free_tmpfile
)
7944 tempfile_unlink (tmpfile
);
7948 Message (_("Unknown import mode: %s\n"), mode
);
7953 AddAllRats (false, NULL
);
7956 printf("ActionImport: =========== Leaving ActionImport ============\n");
7962 /* ------------------------------------------------------------ */
7964 static const char attributes_syntax
[] =
7965 N_("Attributes(Layout|Layer|Element)\n"
7966 "Attributes(Layer,layername)");
7968 static const char attributes_help
[] =
7969 N_("Let the user edit the attributes of the layout, current or given\n"
7970 "layer, or selected element.");
7972 /* %start-doc actions Attributes
7974 This just pops up a dialog letting the user edit the attributes of the
7975 pcb, an element, or a layer.
7981 ActionAttributes (int argc
, char **argv
, Coord x
, Coord y
)
7983 char *function
= ARG (0);
7984 char *layername
= ARG (1);
7990 if (!gui
->edit_attributes
)
7992 Message (_("This GUI doesn't support Attribute Editing\n"));
7996 switch (GetFunctionID (function
))
8000 gui
->edit_attributes(_("Layout Attributes"), &(PCB
->Attributes
));
8006 LayerType
*layer
= CURRENT
;
8011 for (i
=0; i
<max_copper_layer
; i
++)
8012 if (strcmp (PCB
->Data
->Layer
[i
].Name
, layername
) == 0)
8014 layer
= & (PCB
->Data
->Layer
[i
]);
8019 Message (_("No layer named %s\n"), layername
);
8023 buf
= (char *) malloc (strlen (layer
->Name
) +
8024 strlen (_("Layer %s Attributes")));
8025 sprintf (buf
, _("Layer %s Attributes"), layer
->Name
);
8026 gui
->edit_attributes(buf
, &(layer
->Attributes
));
8034 ElementType
*e
= NULL
;
8035 ELEMENT_LOOP (PCB
->Data
);
8037 if (TEST_FLAG (SELECTEDFLAG
, element
))
8046 Message (_("Too many elements selected\n"));
8052 gui
->get_coords (_("Click on an element"), &x
, &y
);
8054 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
8055 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
8056 e
= (ElementType
*) ptrtmp
;
8059 Message (_("No element found there\n"));
8064 if (NAMEONPCB_NAME(e
))
8066 buf
= (char *) malloc (strlen (NAMEONPCB_NAME(e
)) +
8067 strlen (_("Element %s Attributes")));
8068 sprintf(buf
, _("Element %s Attributes"), NAMEONPCB_NAME(e
));
8072 buf
= strdup (_("Unnamed Element Attributes"));
8074 gui
->edit_attributes(buf
, &(e
->Attributes
));
8086 /* --------------------------------------------------------------------------- */
8088 HID_Action action_action_list
[] = {
8089 {"AddRats", 0, ActionAddRats
,
8090 addrats_help
, addrats_syntax
}
8092 {"Attributes", 0, ActionAttributes
,
8093 attributes_help
, attributes_syntax
}
8095 {"Atomic", 0, ActionAtomic
,
8096 atomic_help
, atomic_syntax
}
8098 {"AutoPlaceSelected", 0, ActionAutoPlaceSelected
,
8099 autoplace_help
, autoplace_syntax
}
8101 {"AutoRoute", 0, ActionAutoRoute
,
8102 autoroute_help
, autoroute_syntax
}
8104 {"ChangeClearSize", 0, ActionChangeClearSize
,
8105 changeclearsize_help
, changeclearsize_syntax
}
8107 {"ChangeDrillSize", 0, ActionChange2ndSize
,
8108 changedrillsize_help
, changedrillsize_syntax
}
8110 {"ChangeHole", 0, ActionChangeHole
,
8111 changehold_help
, changehold_syntax
}
8113 {"ChangeJoin", 0, ActionChangeJoin
,
8114 changejoin_help
, changejoin_syntax
}
8116 {"ChangeName", 0, ActionChangeName
,
8117 changename_help
, changename_syntax
}
8119 {"ChangePaste", 0, ActionChangePaste
,
8120 changepaste_help
, changepaste_syntax
}
8122 {"ChangePinName", 0, ActionChangePinName
,
8123 changepinname_help
, changepinname_syntax
}
8125 {"ChangeSize", 0, ActionChangeSize
,
8126 changesize_help
, changesize_syntax
}
8128 {"ChangeSquare", 0, ActionChangeSquare
,
8129 changesquare_help
, changesquare_syntax
}
8131 {"ChangeOctagon", 0, ActionChangeOctagon
,
8132 changeoctagon_help
, changeoctagon_syntax
}
8134 {"ClearSquare", 0, ActionClearSquare
,
8135 clearsquare_help
, clearsquare_syntax
}
8137 {"ClearOctagon", 0, ActionClearOctagon
,
8138 clearoctagon_help
, clearoctagon_syntax
}
8140 {"Connection", 0, ActionConnection
,
8141 connection_help
, connection_syntax
}
8143 {"Delete", 0, ActionDelete
,
8144 delete_help
, delete_syntax
}
8146 {"DeleteRats", 0, ActionDeleteRats
,
8147 deleterats_help
, deleterats_syntax
}
8149 {"DisperseElements", 0, ActionDisperseElements
,
8150 disperseelements_help
, disperseelements_syntax
}
8152 {"Display", 0, ActionDisplay
,
8153 display_help
, display_syntax
}
8155 {"DRC", 0, ActionDRCheck
,
8156 drc_help
, drc_syntax
}
8158 {"DumpLibrary", 0, ActionDumpLibrary
,
8159 dumplibrary_help
, dumplibrary_syntax
}
8161 {"ExecuteFile", 0, ActionExecuteFile
,
8162 executefile_help
, executefile_syntax
}
8164 {"Flip", N_("Click on Object or Flip Point"), ActionFlip
,
8165 flip_help
, flip_syntax
}
8167 {"LoadFrom", 0, ActionLoadFrom
,
8168 loadfrom_help
, loadfrom_syntax
}
8170 {"MarkCrosshair", 0, ActionMarkCrosshair
,
8171 markcrosshair_help
, markcrosshair_syntax
}
8173 {"Message", 0, ActionMessage
,
8174 message_help
, message_syntax
}
8176 {"MinMaskGap", 0, ActionMinMaskGap
,
8177 minmaskgap_help
, minmaskgap_syntax
}
8179 {"MinClearGap", 0, ActionMinClearGap
,
8180 mincleargap_help
, mincleargap_syntax
}
8182 {"Mode", 0, ActionMode
,
8183 mode_help
, mode_syntax
}
8185 {"MorphPolygon", 0, ActionMorphPolygon
,
8186 morphpolygon_help
, morphpolygon_syntax
}
8188 {"PasteBuffer", 0, ActionPasteBuffer
,
8189 pastebuffer_help
, pastebuffer_syntax
}
8191 {"Quit", 0, ActionQuit
,
8192 quit_help
, quit_syntax
}
8194 {"RemoveSelected", 0, ActionRemoveSelected
,
8195 removeselected_help
, removeselected_syntax
}
8197 {"Renumber", 0, ActionRenumber
,
8198 renumber_help
, renumber_syntax
}
8200 {"RipUp", 0, ActionRipUp
,
8201 ripup_help
, ripup_syntax
}
8203 {"Select", 0, ActionSelect
,
8204 select_help
, select_syntax
}
8206 {"Unselect", 0, ActionUnselect
,
8207 unselect_help
, unselect_syntax
}
8209 {"SaveSettings", 0, ActionSaveSettings
,
8210 savesettings_help
, savesettings_syntax
}
8212 {"SaveTo", 0, ActionSaveTo
,
8213 saveto_help
, saveto_syntax
}
8215 {"SetSquare", 0, ActionSetSquare
,
8216 setsquare_help
, setsquare_syntax
}
8218 {"SetOctagon", 0, ActionSetOctagon
,
8219 setoctagon_help
, setoctagon_syntax
}
8221 {"SetThermal", 0, ActionSetThermal
,
8222 setthermal_help
, setthermal_syntax
}
8224 {"SetValue", 0, ActionSetValue
,
8225 setvalue_help
, setvalue_syntax
}
8227 {"ToggleHideName", 0, ActionToggleHideName
,
8228 togglehidename_help
, togglehidename_syntax
}
8230 {"Undo", 0, ActionUndo
,
8231 undo_help
, undo_syntax
}
8233 {"Redo", 0, ActionRedo
,
8234 redo_help
, redo_syntax
}
8236 {"SetSame", N_("Select item to use attributes from"), ActionSetSame
,
8237 setsame_help
, setsame_syntax
}
8239 {"SetFlag", 0, ActionSetFlag
,
8240 setflag_help
, setflag_syntax
}
8242 {"ClrFlag", 0, ActionClrFlag
,
8243 clrflag_help
, clrflag_syntax
}
8245 {"ChangeFlag", 0, ActionChangeFlag
,
8246 changeflag_help
, changeflag_syntax
}
8248 {"Polygon", 0, ActionPolygon
,
8249 polygon_help
, polygon_syntax
}
8251 {"RouteStyle", 0, ActionRouteStyle
,
8252 routestyle_help
, routestyle_syntax
}
8254 {"MoveObject", N_("Select an Object"), ActionMoveObject
,
8255 moveobject_help
, moveobject_syntax
}
8257 {"MoveToCurrentLayer", 0, ActionMoveToCurrentLayer
,
8258 movetocurrentlayer_help
, movetocurrentlayer_syntax
}
8260 {"New", 0, ActionNew
,
8261 new_help
, new_syntax
}
8263 {"pscalib", 0, ActionPSCalib
}
8265 {"ElementList", 0, ActionElementList
,
8266 elementlist_help
, elementlist_syntax
}
8268 {"ElementSetAttr", 0, ActionElementSetAttr
,
8269 elementsetattr_help
, elementsetattr_syntax
}
8271 {"ExecCommand", 0, ActionExecCommand
,
8272 execcommand_help
, execcommand_syntax
}
8274 {"Import", 0, ActionImport
,
8275 import_help
, import_syntax
}
8279 REGISTER_ACTIONS (action_action_list
)