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 RestoreUndoSerialNumber ();
683 SetChangedFlag (true);
687 else if (Note
.Moving
)
689 RestoreUndoSerialNumber ();
691 ClearBuffer (PASTEBUFFER
);
692 SetBufferNumber (Note
.Buffer
);
701 else if (Settings
.Mode
== ARROW_MODE
)
703 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
704 Crosshair
.AttachedBox
.Point2
.X
);
705 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
706 Crosshair
.AttachedBox
.Point2
.Y
);
707 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
708 Crosshair
.AttachedBox
.Point2
.X
);
709 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
710 Crosshair
.AttachedBox
.Point2
.Y
);
711 RestoreUndoSerialNumber ();
712 if (SelectBlock (&box
, true))
713 SetChangedFlag (true);
715 IncrementUndoSerialNumber ();
716 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
724 static char function_hash
[HSIZE
];
725 static int hash_initted
= 0;
734 i
= (i
* 13) ^ (unsigned char)tolower((int) *s
);
737 i
= (unsigned int)i
% HSIZE
;
742 * \brief Get function ID of passed string.
745 GetFunctionID (String Ident
)
755 if (HSIZE
< ENTRIES (Functions
) * 2)
757 fprintf(stderr
, _("Error: function hash size too small (%d vs %lu at %s:%d)\n"),
758 HSIZE
, (unsigned long) ENTRIES (Functions
)*2, __FILE__
, __LINE__
);
761 if (ENTRIES (Functions
) > 254)
763 /* Change 'char' to 'int' and remove this when we get to 256
765 fprintf(stderr
, _("Error: function hash type too small (%d vs %lu at %s:%d)\n"),
766 256, (unsigned long) ENTRIES (Functions
), __FILE__
, __LINE__
);
770 for (i
=ENTRIES (Functions
)-1; i
>=0; i
--)
772 h
= hashfunc (Functions
[i
].Identifier
);
773 while (function_hash
[h
])
775 function_hash
[h
] = i
+ 1;
779 i
= hashfunc (Ident
);
782 /* We enforce the "hash table bigger than function table" rule,
783 so we know there will be at least one zero entry to find. */
784 if (!function_hash
[i
])
786 if (!strcasecmp (Ident
, Functions
[function_hash
[i
]-1].Identifier
))
787 return ((int) Functions
[function_hash
[i
]-1].ID
);
793 * \brief Set new coordinates if in 'RECTANGLE' mode.
795 * The cursor shape is also adjusted.
798 AdjustAttachedBox (void)
800 if (Settings
.Mode
== ARC_MODE
)
802 Crosshair
.AttachedBox
.otherway
= gui
->shift_is_pressed ();
805 switch (Crosshair
.AttachedBox
.State
)
807 case STATE_SECOND
: /* one corner is selected */
809 /* update coordinates */
810 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
811 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
818 * \brief Adjusts the objects which are to be created like attached
822 AdjustAttachedObjects (void)
825 switch (Settings
.Mode
)
827 /* update at least an attached block (selection) */
830 if (Crosshair
.AttachedBox
.State
)
832 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
833 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
837 /* rectangle creation mode */
840 AdjustAttachedBox ();
843 /* polygon creation mode */
845 case POLYGONHOLE_MODE
:
846 AdjustAttachedLine ();
848 /* line creation mode */
850 if (PCB
->RatDraw
|| PCB
->Clipping
== 0)
851 AdjustAttachedLine ();
853 AdjustTwoLine (PCB
->Clipping
- 1);
855 /* point insertion mode */
856 case INSERTPOINT_MODE
:
857 pnt
= AdjustInsertPoint ();
859 InsertedPoint
= *pnt
;
867 * \brief Creates points of a line.
873 void *ptr1
, *ptr2
, *ptr3
;
875 if (!Marked
.status
|| TEST_FLAG (LOCALREFFLAG
, PCB
))
876 SetLocalRef (Crosshair
.X
, Crosshair
.Y
, true);
877 switch (Crosshair
.AttachedLine
.State
)
879 case STATE_FIRST
: /* first point */
880 if (PCB
->RatDraw
&& SearchScreen (Crosshair
.X
, Crosshair
.Y
,
881 PAD_TYPE
| PIN_TYPE
, &ptr1
, &ptr1
,
887 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
889 type
= SearchScreen (Crosshair
.X
, Crosshair
.Y
,
890 PIN_TYPE
| PAD_TYPE
| VIA_TYPE
, &ptr1
, &ptr2
,
892 LookupConnection (Crosshair
.X
, Crosshair
.Y
, true, 1, CONNECTEDFLAG
, false);
893 LookupConnection (Crosshair
.X
, Crosshair
.Y
, true, 1, FOUNDFLAG
, true);
895 if (type
== PIN_TYPE
|| type
== VIA_TYPE
)
897 Crosshair
.AttachedLine
.Point1
.X
=
898 Crosshair
.AttachedLine
.Point2
.X
= ((PinType
*) ptr2
)->X
;
899 Crosshair
.AttachedLine
.Point1
.Y
=
900 Crosshair
.AttachedLine
.Point2
.Y
= ((PinType
*) ptr2
)->Y
;
902 else if (type
== PAD_TYPE
)
904 PadType
*pad
= (PadType
*) ptr2
;
905 double d1
= Distance (Crosshair
.X
, Crosshair
.Y
, pad
->Point1
.X
, pad
->Point1
.Y
);
906 double d2
= Distance (Crosshair
.X
, Crosshair
.Y
, pad
->Point2
.X
, pad
->Point2
.Y
);
909 Crosshair
.AttachedLine
.Point1
=
910 Crosshair
.AttachedLine
.Point2
= pad
->Point2
;
914 Crosshair
.AttachedLine
.Point1
=
915 Crosshair
.AttachedLine
.Point2
= pad
->Point1
;
920 Crosshair
.AttachedLine
.Point1
.X
=
921 Crosshair
.AttachedLine
.Point2
.X
= Crosshair
.X
;
922 Crosshair
.AttachedLine
.Point1
.Y
=
923 Crosshair
.AttachedLine
.Point2
.Y
= Crosshair
.Y
;
925 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
929 /* fall through to third state too */
931 default: /* all following points */
932 Crosshair
.AttachedLine
.State
= STATE_THIRD
;
938 * \brief Create first or second corner of a marked block.
943 notify_crosshair_change (false);
944 switch (Crosshair
.AttachedBox
.State
)
946 case STATE_FIRST
: /* setup first point */
947 Crosshair
.AttachedBox
.Point1
.X
=
948 Crosshair
.AttachedBox
.Point2
.X
= Crosshair
.X
;
949 Crosshair
.AttachedBox
.Point1
.Y
=
950 Crosshair
.AttachedBox
.Point2
.Y
= Crosshair
.Y
;
951 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
954 case STATE_SECOND
: /* setup second point */
955 Crosshair
.AttachedBox
.State
= STATE_THIRD
;
958 notify_crosshair_change (true);
963 * \brief This is called after every mode change, like mouse button pressed,
964 * mouse button released, dragging something started or a different tool
967 * It does what's appropriate for the current mode setting.
968 * This can also mean creation of an object at the current crosshair location.
970 * New created objects are added to the create undo list of course.
975 void *ptr1
, *ptr2
, *ptr3
;
978 if (Settings
.RatWarn
)
980 switch (Settings
.Mode
)
988 /* do something after click time */
989 gui
->add_timer (click_cb
, CLICK_TIME
, hv
);
991 /* see if we clicked on something already selected
992 * (Note.Moving) or clicked on a MOVE_TYPE
995 for (test
= (SELECT_TYPES
| MOVE_TYPES
) & ~RATLINE_TYPE
;
998 type
= SearchScreen (Note
.X
, Note
.Y
, test
, &ptr1
, &ptr2
, &ptr3
);
999 if (!Note
.Hit
&& (type
& MOVE_TYPES
) &&
1000 !TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
1007 if (!Note
.Moving
&& (type
& SELECT_TYPES
) &&
1008 TEST_FLAG (SELECTEDFLAG
, (PinType
*) ptr2
))
1010 if ((Note
.Hit
&& Note
.Moving
) || type
== NO_TYPE
)
1022 Message (_("You must turn via visibility on before\n"
1023 "you can place vias\n"));
1026 if ((via
= CreateNewVia (PCB
->Data
, Note
.X
, Note
.Y
,
1027 Settings
.ViaThickness
, 2 * Settings
.Keepaway
,
1028 0, Settings
.ViaDrillingHole
, NULL
,
1029 NoFlags ())) != NULL
)
1031 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1032 if (gui
->shift_is_pressed ())
1033 ChangeObjectThermal (VIA_TYPE
, via
, via
, via
, PCB
->ThermStyle
);
1034 IncrementUndoSerialNumber ();
1043 switch (Crosshair
.AttachedBox
.State
)
1046 Crosshair
.AttachedBox
.Point1
.X
=
1047 Crosshair
.AttachedBox
.Point2
.X
= Note
.X
;
1048 Crosshair
.AttachedBox
.Point1
.Y
=
1049 Crosshair
.AttachedBox
.Point2
.Y
= Note
.Y
;
1050 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
1060 wx
= Note
.X
- Crosshair
.AttachedBox
.Point1
.X
;
1061 wy
= Note
.Y
- Crosshair
.AttachedBox
.Point1
.Y
;
1062 if (XOR (Crosshair
.AttachedBox
.otherway
, abs (wy
) > abs (wx
)))
1064 Crosshair
.AttachedBox
.Point2
.X
=
1065 Crosshair
.AttachedBox
.Point1
.X
+ abs (wy
) * SGNZ (wx
);
1066 sa
= (wx
>= 0) ? 0 : 180;
1068 if (abs (wy
) / 2 >= abs (wx
))
1069 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 45 : -45;
1072 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? 90 : -90;
1076 Crosshair
.AttachedBox
.Point2
.Y
=
1077 Crosshair
.AttachedBox
.Point1
.Y
+ abs (wx
) * SGNZ (wy
);
1078 sa
= (wy
>= 0) ? -90 : 90;
1080 if (abs (wx
) / 2 >= abs (wy
))
1081 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -45 : 45;
1084 dir
= (SGNZ (wx
) == SGNZ (wy
)) ? -90 : 90;
1087 if (abs (wy
) > 0 && (arc
= CreateNewArcOnLayer (CURRENT
,
1111 bx
= GetArcEnds (arc
);
1112 Crosshair
.AttachedBox
.Point1
.X
=
1113 Crosshair
.AttachedBox
.Point2
.X
= bx
->X2
;
1114 Crosshair
.AttachedBox
.Point1
.Y
=
1115 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y2
;
1116 AddObjectToCreateUndoList (ARC_TYPE
, CURRENT
, arc
, arc
);
1117 IncrementUndoSerialNumber ();
1119 DrawArc (CURRENT
, arc
);
1121 Crosshair
.AttachedBox
.State
= STATE_THIRD
;
1130 type
= SearchScreen (Note
.X
, Note
.Y
, LOCK_TYPES
, &ptr1
, &ptr2
, &ptr3
);
1131 if (type
== ELEMENT_TYPE
)
1133 ElementType
*element
= (ElementType
*) ptr2
;
1135 TOGGLE_FLAG (LOCKFLAG
, element
);
1138 TOGGLE_FLAG (LOCKFLAG
, pin
);
1139 CLEAR_FLAG (SELECTEDFLAG
, pin
);
1144 TOGGLE_FLAG (LOCKFLAG
, pad
);
1145 CLEAR_FLAG (SELECTEDFLAG
, pad
);
1148 CLEAR_FLAG (SELECTEDFLAG
, element
);
1149 /* always re-draw it since I'm too lazy
1150 * to tell if a selected flag changed
1152 DrawElement (element
);
1154 SetChangedFlag (true);
1155 hid_actionl ("Report", "Object", NULL
);
1157 else if (type
!= NO_TYPE
)
1159 TextType
*thing
= (TextType
*) ptr3
;
1160 TOGGLE_FLAG (LOCKFLAG
, thing
);
1161 if (TEST_FLAG (LOCKFLAG
, thing
)
1162 && TEST_FLAG (SELECTEDFLAG
, thing
))
1164 /* this is not un-doable since LOCK isn't */
1165 CLEAR_FLAG (SELECTEDFLAG
, thing
);
1166 DrawObject (type
, ptr1
, ptr2
);
1169 SetChangedFlag (true);
1170 hid_actionl ("Report", "Object", NULL
);
1178 SearchScreen (Note
.X
, Note
.Y
, PIN_TYPES
, &ptr1
, &ptr2
,
1180 && !TEST_FLAG (HOLEFLAG
, (PinType
*) ptr3
))
1182 if (gui
->shift_is_pressed ())
1184 int tstyle
= GET_THERM (INDEXOFCURRENT
, (PinType
*) ptr3
);
1188 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, tstyle
);
1190 else if (GET_THERM (INDEXOFCURRENT
, (PinType
*) ptr3
))
1191 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, 0);
1193 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, PCB
->ThermStyle
);
1199 /* do update of position */
1201 if (Crosshair
.AttachedLine
.State
!= STATE_THIRD
)
1204 /* Remove anchor if clicking on start point;
1205 * this means we can't paint 0 length lines
1206 * which could be used for square SMD pads.
1207 * Instead use a very small delta, or change
1208 * the file after saving.
1210 if (Crosshair
.X
== Crosshair
.AttachedLine
.Point1
.X
1211 && Crosshair
.Y
== Crosshair
.AttachedLine
.Point1
.Y
)
1213 SetMode (LINE_MODE
);
1220 if ((line
= AddNet ()))
1223 AddObjectToCreateUndoList (RATLINE_TYPE
, line
, line
, line
);
1224 IncrementUndoSerialNumber ();
1226 Crosshair
.AttachedLine
.Point1
.X
=
1227 Crosshair
.AttachedLine
.Point2
.X
;
1228 Crosshair
.AttachedLine
.Point1
.Y
=
1229 Crosshair
.AttachedLine
.Point2
.Y
;
1235 /* create line if both ends are determined && length != 0 */
1240 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && !TEST_SILK_LAYER (CURRENT
))
1241 line_flags
|= CONNECTEDFLAG
| FOUNDFLAG
;
1243 if (TEST_FLAG (CLEARNEWFLAG
, PCB
))
1244 line_flags
|= CLEARLINEFLAG
;
1247 && Crosshair
.AttachedLine
.Point1
.X
==
1248 Crosshair
.AttachedLine
.Point2
.X
1249 && Crosshair
.AttachedLine
.Point1
.Y
==
1250 Crosshair
.AttachedLine
.Point2
.Y
1251 && (Crosshair
.AttachedLine
.Point2
.X
!= Note
.X
1252 || Crosshair
.AttachedLine
.Point2
.Y
!= Note
.Y
))
1254 /* We will only need to paint the second line segment.
1255 Since we only check for vias on the first segment,
1256 swap them so the non-empty segment is the first segment. */
1257 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1258 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1261 if ((Crosshair
.AttachedLine
.Point1
.X
!=
1262 Crosshair
.AttachedLine
.Point2
.X
1263 || Crosshair
.AttachedLine
.Point1
.Y
!=
1264 Crosshair
.AttachedLine
.Point2
.Y
))
1269 CreateDrawnLineOnLayer (CURRENT
,
1270 Crosshair
.AttachedLine
.Point1
.X
,
1271 Crosshair
.AttachedLine
.Point1
.Y
,
1272 Crosshair
.AttachedLine
.Point2
.X
,
1273 Crosshair
.AttachedLine
.Point2
.Y
,
1274 Settings
.LineThickness
,
1275 2 * Settings
.Keepaway
,
1276 MakeFlags (line_flags
))) != NULL
)
1280 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1281 DrawLine (CURRENT
, line
);
1283 /* place a via if vias are visible, the layer is
1284 in a new group since the last line and there
1285 isn't a pin already here */
1286 if (PCB
->ViaOn
&& GetLayerGroupNumberByPointer (CURRENT
) !=
1287 GetLayerGroupNumberByPointer (lastLayer
) &&
1288 SearchObjectByLocation (PIN_TYPES
, &ptr1
, &ptr2
, &ptr3
,
1289 Crosshair
.AttachedLine
.Point1
.X
,
1290 Crosshair
.AttachedLine
.Point1
.Y
,
1291 Settings
.ViaThickness
/ 2) ==
1294 CreateNewVia (PCB
->Data
,
1295 Crosshair
.AttachedLine
.Point1
.X
,
1296 Crosshair
.AttachedLine
.Point1
.Y
,
1297 Settings
.ViaThickness
,
1298 2 * Settings
.Keepaway
, 0,
1299 Settings
.ViaDrillingHole
, NULL
,
1300 NoFlags ())) != NULL
)
1302 AddObjectToCreateUndoList (VIA_TYPE
, via
, via
, via
);
1305 /* copy the coordinates */
1306 Crosshair
.AttachedLine
.Point1
.X
=
1307 Crosshair
.AttachedLine
.Point2
.X
;
1308 Crosshair
.AttachedLine
.Point1
.Y
=
1309 Crosshair
.AttachedLine
.Point2
.Y
;
1310 IncrementUndoSerialNumber ();
1311 lastLayer
= CURRENT
;
1313 if (PCB
->Clipping
&& (Note
.X
!= Crosshair
.AttachedLine
.Point2
.X
1315 Crosshair
.AttachedLine
.Point2
.Y
))
1318 CreateDrawnLineOnLayer (CURRENT
,
1319 Crosshair
.AttachedLine
.Point2
.X
,
1320 Crosshair
.AttachedLine
.Point2
.Y
,
1322 Settings
.LineThickness
,
1323 2 * Settings
.Keepaway
,
1324 MakeFlags (line_flags
))) != NULL
)
1327 AddObjectToCreateUndoList (LINE_TYPE
, CURRENT
, line
, line
);
1328 IncrementUndoSerialNumber ();
1329 DrawLine (CURRENT
, line
);
1331 /* move to new start point */
1332 Crosshair
.AttachedLine
.Point1
.X
= Note
.X
;
1333 Crosshair
.AttachedLine
.Point1
.Y
= Note
.Y
;
1334 Crosshair
.AttachedLine
.Point2
.X
= Note
.X
;
1335 Crosshair
.AttachedLine
.Point2
.Y
= Note
.Y
;
1336 if (TEST_FLAG (SWAPSTARTDIRFLAG
, PCB
))
1341 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && !TEST_SILK_LAYER (CURRENT
))
1342 LookupConnection (Note
.X
, Note
.Y
, true, 1, CONNECTEDFLAG
, false);
1347 case RECTANGLE_MODE
:
1348 /* do update of position */
1351 /* create rectangle if both corners are determined
1352 * and width, height are != 0
1354 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
1355 Crosshair
.AttachedBox
.Point1
.X
!= Crosshair
.AttachedBox
.Point2
.X
&&
1356 Crosshair
.AttachedBox
.Point1
.Y
!= Crosshair
.AttachedBox
.Point2
.Y
)
1358 PolygonType
*polygon
;
1360 int flags
= CLEARPOLYFLAG
;
1361 if (TEST_FLAG (NEWFULLPOLYFLAG
, PCB
))
1362 flags
|= FULLPOLYFLAG
;
1363 if ((polygon
= CreateNewPolygonFromRectangle (CURRENT
,
1365 AttachedBox
.Point1
.X
,
1367 AttachedBox
.Point1
.Y
,
1369 AttachedBox
.Point2
.X
,
1371 AttachedBox
.Point2
.Y
,
1376 AddObjectToCreateUndoList (POLYGON_TYPE
, CURRENT
,
1378 IncrementUndoSerialNumber ();
1379 DrawPolygon (CURRENT
, polygon
);
1383 /* reset state to 'first corner' */
1384 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
1392 if ((string
= gui
->prompt_for (_("Enter text:"), "")) != NULL
)
1394 if (strlen(string
) > 0)
1397 int flag
= CLEARLINEFLAG
;
1399 if (GetLayerGroupNumberByNumber (INDEXOFCURRENT
) ==
1400 GetLayerGroupNumberBySide (BOTTOM_SIDE
))
1401 flag
|= ONSOLDERFLAG
;
1402 if ((text
= CreateNewText (CURRENT
, &PCB
->Font
, Note
.X
,
1403 Note
.Y
, 0, Settings
.TextScale
,
1404 string
, MakeFlags (flag
))) != NULL
)
1406 AddObjectToCreateUndoList (TEXT_TYPE
, CURRENT
, text
, text
);
1407 IncrementUndoSerialNumber ();
1408 DrawText (CURRENT
, text
);
1419 PointType
*points
= Crosshair
.AttachedPolygon
.Points
;
1420 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1422 /* do update of position; use the 'LINE_MODE' mechanism */
1425 /* check if this is the last point of a polygon */
1427 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1428 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1430 CopyAttachedPolygonToLayer ();
1435 /* create new point if it's the first one or if it's
1436 * different to the last one
1439 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1440 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1442 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1443 Crosshair
.AttachedLine
.Point2
.X
,
1444 Crosshair
.AttachedLine
.Point2
.Y
);
1446 /* copy the coordinates */
1447 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1448 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1453 case POLYGONHOLE_MODE
:
1455 switch (Crosshair
.AttachedObject
.State
)
1457 /* first notify, lookup object */
1459 Crosshair
.AttachedObject
.Type
=
1460 SearchScreen (Note
.X
, Note
.Y
, POLYGON_TYPE
,
1461 &Crosshair
.AttachedObject
.Ptr1
,
1462 &Crosshair
.AttachedObject
.Ptr2
,
1463 &Crosshair
.AttachedObject
.Ptr3
);
1465 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1467 if (TEST_FLAG (LOCKFLAG
, (PolygonType
*)
1468 Crosshair
.AttachedObject
.Ptr2
))
1470 Message (_("Sorry, the object is locked\n"));
1471 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1475 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1479 /* second notify, insert new point into object */
1482 PointType
*points
= Crosshair
.AttachedPolygon
.Points
;
1483 Cardinal n
= Crosshair
.AttachedPolygon
.PointN
;
1484 POLYAREA
*original
, *new_hole
, *result
;
1487 /* do update of position; use the 'LINE_MODE' mechanism */
1490 /* check if this is the last point of a polygon */
1492 points
->X
== Crosshair
.AttachedLine
.Point2
.X
&&
1493 points
->Y
== Crosshair
.AttachedLine
.Point2
.Y
)
1495 /* Create POLYAREAs from the original polygon
1496 * and the new hole polygon */
1497 original
= PolygonToPoly ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
);
1498 new_hole
= PolygonToPoly (&Crosshair
.AttachedPolygon
);
1500 /* Subtract the hole from the original polygon shape */
1501 poly_Boolean_free (original
, new_hole
, &result
, PBO_SUB
);
1503 /* Convert the resulting polygon(s) into a new set of nodes
1504 * and place them on the page. Delete the original polygon.
1506 SaveUndoSerialNumber ();
1507 Flags
= ((PolygonType
*)Crosshair
.AttachedObject
.Ptr2
)->Flags
;
1508 PolyToPolygonsOnLayer (PCB
->Data
, (LayerType
*)Crosshair
.AttachedObject
.Ptr1
,
1510 RemoveObject (POLYGON_TYPE
,
1511 Crosshair
.AttachedObject
.Ptr1
,
1512 Crosshair
.AttachedObject
.Ptr2
,
1513 Crosshair
.AttachedObject
.Ptr3
);
1514 RestoreUndoSerialNumber ();
1515 IncrementUndoSerialNumber ();
1518 /* reset state of attached line */
1519 memset (&Crosshair
.AttachedPolygon
, 0, sizeof (PolygonType
));
1520 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
1526 /* create new point if it's the first one or if it's
1527 * different to the last one
1530 points
[n
- 1].X
!= Crosshair
.AttachedLine
.Point2
.X
||
1531 points
[n
- 1].Y
!= Crosshair
.AttachedLine
.Point2
.Y
)
1533 CreateNewPointInPolygon (&Crosshair
.AttachedPolygon
,
1534 Crosshair
.AttachedLine
.Point2
.X
,
1535 Crosshair
.AttachedLine
.Point2
.Y
);
1537 /* copy the coordinates */
1538 Crosshair
.AttachedLine
.Point1
.X
= Crosshair
.AttachedLine
.Point2
.X
;
1539 Crosshair
.AttachedLine
.Point1
.Y
= Crosshair
.AttachedLine
.Point2
.Y
;
1548 case PASTEBUFFER_MODE
:
1550 TextType estr
[MAX_ELEMENTNAMES
];
1553 if (gui
->shift_is_pressed ())
1556 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1558 if (type
== ELEMENT_TYPE
)
1560 e
= (ElementType
*) ptr1
;
1565 memcpy (estr
, e
->Name
,
1566 MAX_ELEMENTNAMES
* sizeof (TextType
));
1567 for (i
= 0; i
< MAX_ELEMENTNAMES
; ++i
)
1568 estr
[i
].TextString
= estr
[i
].TextString
? strdup(estr
[i
].TextString
) : NULL
;
1573 if (CopyPastebufferToLayout (Note
.X
, Note
.Y
))
1574 SetChangedFlag (true);
1578 SearchScreen (Note
.X
, Note
.Y
, ELEMENT_TYPE
, &ptr1
, &ptr2
,
1580 if (type
== ELEMENT_TYPE
&& ptr1
)
1583 e
= (ElementType
*) ptr1
;
1585 save_n
= NAME_INDEX (PCB
);
1587 for (i
= 0; i
< MAX_ELEMENTNAMES
; i
++)
1590 EraseElementName (e
);
1591 r_delete_entry (PCB
->Data
->name_tree
[i
],
1592 (BoxType
*) & (e
->Name
[i
]));
1593 memcpy (&(e
->Name
[i
]), &(estr
[i
]), sizeof (TextType
));
1594 e
->Name
[i
].Element
= e
;
1595 SetTextBoundingBox (&PCB
->Font
, &(e
->Name
[i
]));
1596 r_insert_entry (PCB
->Data
->name_tree
[i
],
1597 (BoxType
*) & (e
->Name
[i
]), 0);
1599 DrawElementName (e
);
1608 SearchScreen (Note
.X
, Note
.Y
, REMOVE_TYPES
, &ptr1
, &ptr2
,
1611 if (TEST_FLAG (LOCKFLAG
, (LineType
*) ptr2
))
1613 Message (_("Sorry, the object is locked\n"));
1616 if (type
== ELEMENT_TYPE
)
1618 RubberbandType
*ptr
;
1621 Crosshair
.AttachedObject
.RubberbandN
= 0;
1622 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
1623 ptr
= Crosshair
.AttachedObject
.Rubberband
;
1624 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
; i
++)
1627 EraseRat ((RatType
*) ptr
->Line
);
1628 if (TEST_FLAG (RUBBERENDFLAG
, ptr
->Line
))
1629 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
1630 ptr
->Line
, ptr
->Line
,
1633 TOGGLE_FLAG (RUBBERENDFLAG
, ptr
->Line
); /* only remove line once */
1637 RemoveObject (type
, ptr1
, ptr2
, ptr3
);
1638 IncrementUndoSerialNumber ();
1639 SetChangedFlag (true);
1644 RotateScreenObject (Note
.X
, Note
.Y
,
1645 gui
->shift_is_pressed ()? (SWAP_IDENT
?
1647 : (SWAP_IDENT
? 3 : 1));
1650 /* both are almost the same */
1653 switch (Crosshair
.AttachedObject
.State
)
1655 /* first notify, lookup object */
1658 int types
= (Settings
.Mode
== COPY_MODE
) ?
1659 COPY_TYPES
: MOVE_TYPES
;
1661 Crosshair
.AttachedObject
.Type
=
1662 SearchScreen (Note
.X
, Note
.Y
, types
,
1663 &Crosshair
.AttachedObject
.Ptr1
,
1664 &Crosshair
.AttachedObject
.Ptr2
,
1665 &Crosshair
.AttachedObject
.Ptr3
);
1666 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1668 if (Settings
.Mode
== MOVE_MODE
&&
1669 TEST_FLAG (LOCKFLAG
, (PinType
*)
1670 Crosshair
.AttachedObject
.Ptr2
))
1672 Message (_("Sorry, the object is locked\n"));
1673 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1676 AttachForCopy (Note
.X
, Note
.Y
);
1681 /* second notify, move or copy object */
1683 if (Settings
.Mode
== COPY_MODE
)
1684 CopyObject (Crosshair
.AttachedObject
.Type
,
1685 Crosshair
.AttachedObject
.Ptr1
,
1686 Crosshair
.AttachedObject
.Ptr2
,
1687 Crosshair
.AttachedObject
.Ptr3
,
1688 Note
.X
- Crosshair
.AttachedObject
.X
,
1689 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1692 MoveObjectAndRubberband (Crosshair
.AttachedObject
.Type
,
1693 Crosshair
.AttachedObject
.Ptr1
,
1694 Crosshair
.AttachedObject
.Ptr2
,
1695 Crosshair
.AttachedObject
.Ptr3
,
1696 Note
.X
- Crosshair
.AttachedObject
.X
,
1697 Note
.Y
- Crosshair
.AttachedObject
.Y
);
1698 SetLocalRef (0, 0, false);
1700 SetChangedFlag (true);
1702 /* reset identifiers */
1703 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1704 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1709 /* insert a point into a polygon/line/... */
1710 case INSERTPOINT_MODE
:
1711 switch (Crosshair
.AttachedObject
.State
)
1713 /* first notify, lookup object */
1715 Crosshair
.AttachedObject
.Type
=
1716 SearchScreen (Note
.X
, Note
.Y
, INSERT_TYPES
,
1717 &Crosshair
.AttachedObject
.Ptr1
,
1718 &Crosshair
.AttachedObject
.Ptr2
,
1719 &Crosshair
.AttachedObject
.Ptr3
);
1721 if (Crosshair
.AttachedObject
.Type
!= NO_TYPE
)
1723 if (TEST_FLAG (LOCKFLAG
, (PolygonType
*)
1724 Crosshair
.AttachedObject
.Ptr2
))
1726 Message (_("Sorry, the object is locked\n"));
1727 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1732 /* get starting point of nearest segment */
1733 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1736 (PolygonType
*) Crosshair
.AttachedObject
.Ptr2
;
1738 GetLowestDistancePolygonPoint (fake
.poly
, Note
.X
,
1740 fake
.line
.Point1
= fake
.poly
->Points
[polyIndex
];
1741 fake
.line
.Point2
= fake
.poly
->Points
[
1742 prev_contour_point (fake
.poly
, polyIndex
)];
1743 Crosshair
.AttachedObject
.Ptr2
= &fake
.line
;
1746 Crosshair
.AttachedObject
.State
= STATE_SECOND
;
1747 InsertedPoint
= *AdjustInsertPoint ();
1752 /* second notify, insert new point into object */
1754 if (Crosshair
.AttachedObject
.Type
== POLYGON_TYPE
)
1755 InsertPointIntoObject (POLYGON_TYPE
,
1756 Crosshair
.AttachedObject
.Ptr1
, fake
.poly
,
1758 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1760 InsertPointIntoObject (Crosshair
.AttachedObject
.Type
,
1761 Crosshair
.AttachedObject
.Ptr1
,
1762 Crosshair
.AttachedObject
.Ptr2
,
1764 InsertedPoint
.X
, InsertedPoint
.Y
, false, false);
1765 SetChangedFlag (true);
1767 /* reset identifiers */
1768 Crosshair
.AttachedObject
.Type
= NO_TYPE
;
1769 Crosshair
.AttachedObject
.State
= STATE_FIRST
;
1777 /* --------------------------------------------------------------------------- */
1779 static const char atomic_syntax
[] = N_("Atomic(Save|Restore|Close|Block)");
1781 static const char atomic_help
[] = N_("Save or restore the undo serial number.");
1783 /* %start-doc actions Atomic
1785 This action allows making multiple-action bindings into an atomic
1786 operation that will be undone by a single Undo command. For example,
1787 to optimize rat lines, you'd delete the rats and re-add them. To
1788 group these into a single undo, you'd want the deletions and the
1789 additions to have the same undo serial number. So, you @code{Save},
1790 delete the rats, @code{Restore}, add the rats - using the same serial
1791 number as the deletes, then @code{Block}, which checks to see if the
1792 deletions or additions actually did anything. If not, the serial
1793 number is set to the saved number, as there's nothing to undo. If
1794 something did happen, the serial number is incremented so that these
1795 actions are counted as a single undo step.
1800 Saves the undo serial number.
1803 Returns it to the last saved number.
1806 Sets it to 1 greater than the last save.
1809 Does a Restore if there was nothing to undo, else does a Close.
1816 ActionAtomic (int argc
, char **argv
, Coord x
, Coord y
)
1821 switch (GetFunctionID (argv
[0]))
1824 SaveUndoSerialNumber ();
1827 RestoreUndoSerialNumber ();
1830 RestoreUndoSerialNumber ();
1831 IncrementUndoSerialNumber ();
1834 RestoreUndoSerialNumber ();
1836 IncrementUndoSerialNumber ();
1842 /* -------------------------------------------------------------------------- */
1844 static const char drc_syntax
[] = N_("DRC()");
1846 static const char drc_help
[] = N_("Invoke the DRC check.");
1848 /* %start-doc actions DRC
1850 Note that the design rule check uses the current board rule settings,
1851 not the current style settings.
1856 ActionDRCheck (int argc
, char **argv
, Coord x
, Coord y
)
1860 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1862 Message (_("%m+Rules are minspace %$mS, minoverlap %$mS "
1863 "minwidth %$mS, minsilk %$mS\n"
1864 "min drill %$mS, min annular ring %$mS\n"),
1865 Settings
.grid_unit
->allow
,
1866 PCB
->Bloat
, PCB
->Shrink
,
1867 PCB
->minWid
, PCB
->minSlk
,
1868 PCB
->minDrill
, PCB
->minRing
);
1871 if (gui
->drc_gui
== NULL
|| gui
->drc_gui
->log_drc_overview
)
1874 Message (_("No DRC problems found.\n"));
1876 Message (_("Found %d design rule errors.\n"), count
);
1878 Message (_("Aborted DRC after %d design rule errors.\n"), -count
);
1883 /* -------------------------------------------------------------------------- */
1885 static const char dumplibrary_syntax
[] = N_("DumpLibrary()");
1887 static const char dumplibrary_help
[] =
1888 N_("Display the entire contents of the libraries.");
1890 /* %start-doc actions DumpLibrary
1896 ActionDumpLibrary (int argc
, char **argv
, Coord x
, Coord y
)
1900 printf ("**** Do not count on this format. It will change ****\n\n");
1901 printf ("MenuN = %d\n", (int) Library
.MenuN
);
1902 printf ("MenuMax = %d\n", (int) Library
.MenuMax
);
1903 for (i
= 0; i
< Library
.MenuN
; i
++)
1905 printf ("Library #%d:\n", i
);
1906 printf (" EntryN = %d\n", (int) Library
.Menu
[i
].EntryN
);
1907 printf (" EntryMax = %d\n", (int) Library
.Menu
[i
].EntryMax
);
1908 printf (" Name = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Name
));
1909 printf (" directory = \"%s\"\n",
1910 UNKNOWN (Library
.Menu
[i
].directory
));
1911 printf (" Style = \"%s\"\n", UNKNOWN (Library
.Menu
[i
].Style
));
1912 printf (" flag = %d\n", Library
.Menu
[i
].flag
);
1914 for (j
= 0; j
< Library
.Menu
[i
].EntryN
; j
++)
1916 printf (" #%4d: ", j
);
1917 if (Library
.Menu
[i
].Entry
[j
].Template
== (char *) -1)
1919 printf ("newlib: \"%s\"\n",
1920 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
));
1924 printf ("\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"\n",
1925 UNKNOWN (Library
.Menu
[i
].Entry
[j
].ListEntry
),
1926 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Template
),
1927 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Package
),
1928 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Value
),
1929 UNKNOWN (Library
.Menu
[i
].Entry
[j
].Description
));
1937 /* -------------------------------------------------------------------------- */
1939 static const char flip_syntax
[] = N_("Flip(Object|Selected|SelectedElements)");
1941 static const char flip_help
[] =
1942 N_("Flip an element to the opposite side of the board.");
1944 /* %start-doc actions Flip
1946 Note that the location of the element will be symmetric about the
1947 cursor location; i.e. if the part you are pointing at will still be at
1948 the same spot once the element is on the other side. When flipping
1949 multiple elements, this retains their positions relative to each
1950 other, not their absolute positions on the board.
1955 ActionFlip (int argc
, char **argv
, Coord x
, Coord y
)
1957 char *function
= ARG (0);
1958 ElementType
*element
;
1964 switch (GetFunctionID (function
))
1967 if ((SearchScreen (x
, y
, ELEMENT_TYPE
,
1968 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
1970 element
= (ElementType
*) ptrtmp
;
1971 ChangeElementSide (element
, 2 * Crosshair
.Y
- PCB
->MaxHeight
);
1972 IncrementUndoSerialNumber ();
1977 case F_SelectedElements
:
1978 ChangeSelectedElementSide ();
1991 /* -------------------------------------------------------------------------- */
1993 static const char message_syntax
[] = N_("Message(message)");
1995 static const char message_help
[] = N_("Writes a message to the log window.");
1997 /* %start-doc actions Message
1999 This action displays a message to the log window. This action is primarily
2000 provided for use by other programs which may interface with PCB. If
2001 multiple arguments are given, each one is sent to the log window
2002 followed by a newline.
2007 ActionMessage (int argc
, char **argv
, Coord x
, Coord y
)
2014 for (i
= 0; i
< argc
; i
++)
2024 /* -------------------------------------------------------------------------- */
2026 static const char setthermal_syntax
[] =
2027 "SetThermal(Object|SelectedPins|SelectedVias|Selected, Style)";
2029 static const char setthermal_help
[] =
2030 N_("Set the thermal (on the current layer) of pins or vias to the given style.\n"
2031 "Style = 0 means no thermal.\n"
2032 "Style = 1 has diagonal fingers with sharp edges.\n"
2033 "Style = 2 has horizontal and vertical fingers with sharp edges.\n"
2034 "Style = 3 is a solid connection to the plane.\n"
2035 "Style = 4 has diagonal fingers with rounded edges.\n"
2036 "Style = 5 has horizontal and vertical fingers with rounded edges.\n");
2038 /* %start-doc actions SetThermal
2040 This changes how/whether pins or vias connect to any rectangle or polygon
2041 on the current layer. The first argument can specify one object, or all
2042 selected pins, or all selected vias, or all selected pins and vias.
2043 The second argument specifies the style of connection.
2044 There are 5 possibilities:
2046 1 - 45 degree fingers with sharp edges,
2047 2 - horizontal & vertical fingers with sharp edges,
2048 3 - solid connection,
2049 4 - 45 degree fingers with rounded corners,
2050 5 - horizontal & vertical fingers with rounded corners.
2052 Pins and Vias may have thermals whether or not there is a polygon available
2053 to connect with. However, they will have no effect without the polygon.
2057 ActionSetThermal (int argc
, char **argv
, Coord x
, Coord y
)
2059 char *function
= ARG (0);
2060 char *style
= ARG (1);
2061 void *ptr1
, *ptr2
, *ptr3
;
2065 if (function
&& *function
)
2069 if ( ! style
|| ! *style
)
2071 kind
= PCB
->ThermStyle
;
2075 kind
= GetUnitlessValue (style
, &absolute
);
2077 /* To allow relative values we could search for the first selected
2078 item and make 'kind' relative to that, but that's not too useful
2079 and requires quite some code. For example there's no
2080 GetFirstSelectedPin() function available. Let's postpone this
2081 functionality, there are more urgent things to do. */
2084 switch (GetFunctionID (function
))
2088 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGETHERMAL_TYPES
,
2089 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
2091 ChangeObjectThermal (type
, ptr1
, ptr2
, ptr3
, kind
);
2092 IncrementUndoSerialNumber ();
2096 case F_SelectedPins
:
2097 ChangeSelectedThermals (PIN_TYPE
, kind
);
2099 case F_SelectedVias
:
2100 ChangeSelectedThermals (VIA_TYPE
, kind
);
2103 case F_SelectedElements
:
2104 ChangeSelectedThermals (CHANGETHERMAL_TYPES
, kind
);
2123 * \brief Event handler to set the cursor according to the X pointer
2124 * position called from inside main.c.
2126 * \warning !!! no action routine !!!
2129 EventMoveCrosshair (int ev_x
, int ev_y
)
2131 #ifdef HAVE_LIBSTROKE
2134 StrokeBox
.X2
= ev_x
;
2135 StrokeBox
.Y2
= ev_y
;
2136 stroke_record (ev_x
, ev_y
);
2139 #endif /* HAVE_LIBSTROKE */
2140 if (MoveCrosshairAbsolute (ev_x
, ev_y
))
2142 /* update object position and cursor location */
2143 AdjustAttachedObjects ();
2144 notify_crosshair_change (true);
2148 /* --------------------------------------------------------------------------- */
2150 static const char setvalue_syntax
[] =
2151 N_("SetValue(Grid|Line|LineSize|Text|TextScale|ViaDrillingHole|Via|ViaSize, "
2154 static const char setvalue_help
[] =
2155 N_("Change various board-wide values and sizes.");
2157 /* %start-doc actions SetValue
2161 @item ViaDrillingHole
2162 Changes the diameter of the drill for new vias.
2165 Sets the grid spacing.
2169 Changes the thickness of new lines.
2173 Changes the diameter of new vias.
2177 Changes the size of new text.
2184 ActionSetValue (int argc
, char **argv
, Coord x
, Coord y
)
2186 char *function
= ARG (0);
2187 char *val
= ARG (1);
2188 char *units
= ARG (2);
2189 bool absolute
; /* flag for 'absolute' value */
2194 if (function
&& val
)
2196 value
= GetValue (val
, units
, &absolute
);
2197 switch (GetFunctionID (function
))
2199 case F_ViaDrillingHole
:
2200 SetViaDrillingHole (absolute
? value
:
2201 value
+ Settings
.ViaDrillingHole
,
2203 hid_action ("RouteStylesChanged");
2208 SetGrid (value
, false);
2212 value
= val
[0] == '-' ? -Settings
.increments
->grid
2213 : Settings
.increments
->grid
;
2214 /* On the way down, short against the minimum
2215 * PCB drawing unit */
2216 if ((value
+ PCB
->Grid
) < 1)
2218 else if (PCB
->Grid
== 1)
2219 SetGrid (value
, false);
2221 SetGrid (value
+ PCB
->Grid
, false);
2227 if (!absolute
&& value
== 0)
2228 value
= val
[0] == '-' ? -Settings
.increments
->line
2229 : Settings
.increments
->line
;
2230 SetLineSize (absolute
? value
: value
+ Settings
.LineThickness
);
2231 hid_action ("RouteStylesChanged");
2236 SetViaSize (absolute
? value
: value
+ Settings
.ViaThickness
, false);
2237 hid_action ("RouteStylesChanged");
2242 text_scale
= value
/ (double)FONT_CAPHEIGHT
* 100.;
2244 text_scale
+= Settings
.TextScale
;
2245 SetTextScale (text_scale
);
2259 /* --------------------------------------------------------------------------- */
2261 static const char quit_syntax
[] = N_("Quit()");
2263 static const char quit_help
[] = N_("Quits the application after confirming.");
2265 /* %start-doc actions Quit
2267 If you have unsaved changes, you will be prompted to confirm (or
2268 save) before quitting.
2273 ActionQuit (int argc
, char **argv
, Coord x
, Coord y
)
2275 char *force
= ARG (0);
2276 if (force
&& strcasecmp (force
, "force") == 0)
2281 if (!PCB
->Changed
|| gui
->close_confirm_dialog () == HID_CLOSE_CONFIRM_OK
)
2286 /* --------------------------------------------------------------------------- */
2288 static const char connection_syntax
[] =
2289 N_("Connection(Find|ResetLinesAndPolygons|ResetPinsAndVias|Reset)");
2291 static const char connection_help
[] =
2292 N_("Searches connections of the object at the cursor position.");
2294 /* %start-doc actions Connection
2296 Connections found with this action will be highlighted in the
2297 ``connected-color'' color and will have the ``found'' flag set.
2302 The net under the cursor is ``found''.
2304 @item ResetLinesAndPolygons
2305 Any ``found'' lines and polygons are marked ``not found''.
2307 @item ResetPinsAndVias
2308 Any ``found'' pins and vias are marked ``not found''.
2311 All ``found'' objects are marked ``not found''.
2318 ActionConnection (int argc
, char **argv
, Coord x
, Coord y
)
2320 char *function
= ARG (0);
2323 switch (GetFunctionID (function
))
2327 gui
->get_coords (_("Click on a connection"), &x
, &y
);
2328 LookupConnection (x
, y
, true, 1, CONNECTEDFLAG
, false);
2329 LookupConnection (x
, y
, true, 1, FOUNDFLAG
, true);
2333 case F_ResetLinesAndPolygons
:
2334 if (ClearFlagOnLinesAndPolygons (true, CONNECTEDFLAG
| FOUNDFLAG
))
2336 IncrementUndoSerialNumber ();
2341 case F_ResetPinsViasAndPads
:
2342 if (ClearFlagOnPinsViasAndPads (true, CONNECTEDFLAG
| FOUNDFLAG
))
2344 IncrementUndoSerialNumber ();
2350 if (ClearFlagOnAllObjects (true, CONNECTEDFLAG
| FOUNDFLAG
))
2352 IncrementUndoSerialNumber ();
2363 /* --------------------------------------------------------------------------- */
2365 static const char disperseelements_syntax
[] =
2366 N_("DisperseElements(All|Selected)");
2368 static const char disperseelements_help
[] = N_("Disperses elements.");
2370 /* %start-doc actions DisperseElements
2372 Normally this is used when starting a board, by selecting all elements
2373 and then dispersing them. This scatters the elements around the board
2374 so that you can pick individual ones, rather than have all the
2375 elements at the same 0,0 coordinate and thus impossible to choose
2380 #define GAP MIL_TO_COORD(100)
2383 ActionDisperseElements (int argc
, char **argv
, Coord x
, Coord y
)
2385 char *function
= ARG (0);
2390 int all
= 0, bad
= 0;
2392 if (!function
|| !*function
)
2398 switch (GetFunctionID (function
))
2415 AFAIL (disperseelements
);
2419 ELEMENT_LOOP (PCB
->Data
);
2422 * If we want to disperse selected elements, maybe we need smarter
2423 * code here to avoid putting components on top of others which
2424 * are not selected. For now, I'm assuming that this is typically
2425 * going to be used either with a brand new design or a scratch
2426 * design holding some new components
2428 if (!TEST_FLAG (LOCKFLAG
, element
) && (all
|| TEST_FLAG (SELECTEDFLAG
, element
)))
2431 /* figure out how much to move the element */
2432 dx
= minx
- element
->BoundingBox
.X1
;
2434 /* snap to the grid */
2435 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2438 * and add one grid size so we make sure we always space by GAP or
2443 /* Figure out if this row has room. If not, start a new row */
2444 if (GAP
+ element
->BoundingBox
.X2
+ dx
> PCB
->MaxWidth
)
2450 /* figure out how much to move the element */
2451 dx
= minx
- element
->BoundingBox
.X1
;
2452 dy
= miny
- element
->BoundingBox
.Y1
;
2454 /* snap to the grid */
2455 dx
-= (element
->MarkX
+ dx
) % PCB
->Grid
;
2457 dy
-= (element
->MarkY
+ dy
) % PCB
->Grid
;
2460 /* move the element */
2461 MoveElementLowLevel (PCB
->Data
, element
, dx
, dy
);
2463 /* and add to the undo list so we can undo this operation */
2464 AddObjectToMoveUndoList (ELEMENT_TYPE
, NULL
, NULL
, element
, dx
, dy
);
2466 /* keep track of how tall this row is */
2467 minx
+= element
->BoundingBox
.X2
- element
->BoundingBox
.X1
+ GAP
;
2468 if (maxy
< element
->BoundingBox
.Y2
)
2470 maxy
= element
->BoundingBox
.Y2
;
2477 /* done with our action so increment the undo # */
2478 IncrementUndoSerialNumber ();
2481 SetChangedFlag (true);
2488 /* --------------------------------------------------------------------------- */
2490 static const char display_syntax
[] =
2491 N_("Display(NameOnPCB|Description|Value)\n"
2492 "Display(Grid|Redraw)\n"
2493 "Display(CycleClip|CycleCrosshair|Toggle45Degree|ToggleStartDirection)\n"
2494 "Display(ToggleGrid|ToggleRubberBandMode|ToggleUniqueNames)\n"
2495 "Display(ToggleMask|ToggleName|ToggleClearLine|ToggleFullPoly|ToggleSnapPin)\n"
2496 "Display(ToggleThindraw|ToggleThindrawPoly|ToggleOrthoMove|ToggleLocalRef)\n"
2497 "Display(ToggleCheckPlanes|ToggleShowDRC|ToggleAutoDRC)\n"
2498 "Display(ToggleLiveRoute|LockNames|OnlyNames)\n"
2499 "Display(Pinout|PinOrPadName)");
2501 static const char display_help
[] = N_("Several display-related actions.");
2503 /* %start-doc actions Display
2510 Specify whether all elements show their name, description, or value.
2513 Redraw the whole board.
2515 @item Toggle45Degree
2516 When clear, lines can be drawn at any angle. When set, lines are
2517 restricted to multiples of 45 degrees and requested lines may be
2518 broken up according to the clip setting.
2521 Changes the way lines are restricted to 45 degree increments. The
2522 various settings are: straight only, orthogonal then angled, and angled
2523 then orthogonal. If AllDirections is set, this action disables it.
2525 @item CycleCrosshair
2526 Changes crosshair drawing. Crosshair may accept form of 4-ray,
2527 8-ray and 12-ray cross.
2529 @item ToggleRubberBandMode
2530 If set, moving an object moves all the lines attached to it too.
2532 @item ToggleStartDirection
2533 If set, each time you set a point in a line, the Clip toggles between
2534 orth-angle and angle-ortho.
2536 @item ToggleUniqueNames
2537 If set, you will not be permitted to change the name of an element to
2538 match that of another element.
2541 If set, pin centers and pad end points are treated as additional grid
2542 points that the cursor can snap to.
2544 @item ToggleLocalRef
2545 If set, the mark is automatically set to the beginning of any move, so
2546 you can see the relative distance you've moved.
2548 @item ToggleThindraw
2549 If set, objects on the screen are drawn as outlines (lines are drawn
2550 as center-lines). This lets you see line endpoints hidden under pins,
2553 @item ToggleThindrawPoly
2554 If set, polygons on the screen are drawn as outlines.
2557 If set, pending objects (i.e. lines you're in the process of drawing)
2558 will be drawn with an outline showing how far away from other copper
2561 @item ToggleLiveRoute
2562 If set, the progress of the autorouter will be visible on the screen.
2565 If set, you will not be permitted to make connections which violate
2566 the current DRC and netlist settings.
2568 @item ToggleCheckPlanes
2569 If set, lines and arcs aren't drawn, which usually leaves just the
2570 polygons. If you also disable all but the layer you're interested in,
2571 this allows you to check for isolated regions.
2573 @item ToggleOrthoMove
2574 If set, the crosshair is only allowed to move orthogonally from its
2575 previous position. I.e. you can move an element or line up, down,
2576 left, or right, but not up+left or down+right.
2579 Selects whether the pinouts show the pin names or the pin numbers.
2581 @item ToggleLockNames
2582 If set, text will ignore left mouse clicks and actions that work on
2583 objects under the mouse. You can still select text with a lasso (left
2584 mouse drag) and perform actions on the selection.
2586 @item ToggleOnlyNames
2587 If set, only text will be sensitive for mouse clicks and actions that
2588 work on objects under the mouse. You can still select other objects
2589 with a lasso (left mouse drag) and perform actions on the selection.
2592 Turns the solder mask on or off.
2594 @item ToggleClearLine
2595 When set, the clear-line flag causes new lines and arcs to have their
2596 ``clear polygons'' flag set, so they won't be electrically connected
2597 to any polygons they overlap.
2599 @item ToggleFullPoly
2600 When set, the full-poly flag causes new polygons to have their
2601 ``full polygon'' flag set, so all parts of them will be displayed
2602 instead of only the biggest one.
2605 Resets the origin of the current grid to be wherever the mouse pointer
2606 is (not where the crosshair currently is). If you provide two numbers
2607 after this, the origin is set to that coordinate.
2610 Toggles whether the grid is displayed or not.
2613 Causes the pinout of the element indicated by the cursor to be
2614 displayed, usually in a separate window.
2617 Toggles whether the names of pins, pads, or (yes) vias will be
2618 displayed. If the cursor is over an element, all of its pins and pads
2625 static enum crosshair_shape
2626 CrosshairShapeIncrement (enum crosshair_shape shape
)
2630 case Basic_Crosshair_Shape
:
2631 shape
= Union_Jack_Crosshair_Shape
;
2633 case Union_Jack_Crosshair_Shape
:
2634 shape
= Dozen_Crosshair_Shape
;
2636 case Dozen_Crosshair_Shape
:
2637 shape
= Crosshair_Shapes_Number
;
2639 case Crosshair_Shapes_Number
:
2640 shape
= Basic_Crosshair_Shape
;
2647 ActionDisplay (int argc
, char **argv
, Coord childX
, Coord childY
)
2649 char *function
, *str_dir
;
2656 if (function
&& (!str_dir
|| !*str_dir
))
2658 switch (id
= GetFunctionID (function
))
2662 case F_ClearAndRedraw
:
2667 /* change the displayed name of elements */
2671 ELEMENT_LOOP (PCB
->Data
);
2673 EraseElementName (element
);
2676 CLEAR_FLAG (DESCRIPTIONFLAG
| NAMEONPCBFLAG
, PCB
);
2682 SET_FLAG (NAMEONPCBFLAG
, PCB
);
2685 SET_FLAG (DESCRIPTIONFLAG
, PCB
);
2688 ELEMENT_LOOP (PCB
->Data
);
2690 DrawElementName (element
);
2696 /* toggle line-adjust flag */
2697 case F_ToggleAllDirections
:
2698 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2699 AdjustAttachedObjects ();
2703 notify_crosshair_change (false);
2704 if (TEST_FLAG (ALLDIRECTIONFLAG
, PCB
))
2706 TOGGLE_FLAG (ALLDIRECTIONFLAG
, PCB
);
2710 PCB
->Clipping
= (PCB
->Clipping
+ 1) % 3;
2711 AdjustAttachedObjects ();
2712 notify_crosshair_change (true);
2715 case F_CycleCrosshair
:
2716 notify_crosshair_change (false);
2717 Crosshair
.shape
= CrosshairShapeIncrement(Crosshair
.shape
);
2718 if (Crosshair_Shapes_Number
== Crosshair
.shape
)
2719 Crosshair
.shape
= Basic_Crosshair_Shape
;
2720 notify_crosshair_change (true);
2723 case F_ToggleRubberBandMode
:
2724 notify_crosshair_change (false);
2725 TOGGLE_FLAG (RUBBERBANDFLAG
, PCB
);
2726 notify_crosshair_change (true);
2729 case F_ToggleStartDirection
:
2730 notify_crosshair_change (false);
2731 TOGGLE_FLAG (SWAPSTARTDIRFLAG
, PCB
);
2732 notify_crosshair_change (true);
2735 case F_ToggleUniqueNames
:
2736 TOGGLE_FLAG (UNIQUENAMEFLAG
, PCB
);
2739 case F_ToggleSnapPin
:
2740 notify_crosshair_change (false);
2741 TOGGLE_FLAG (SNAPPINFLAG
, PCB
);
2742 notify_crosshair_change (true);
2745 case F_ToggleLocalRef
:
2746 TOGGLE_FLAG (LOCALREFFLAG
, PCB
);
2749 case F_ToggleThindraw
:
2750 TOGGLE_FLAG (THINDRAWFLAG
, PCB
);
2754 case F_ToggleThindrawPoly
:
2755 TOGGLE_FLAG (THINDRAWPOLYFLAG
, PCB
);
2759 case F_ToggleLockNames
:
2760 TOGGLE_FLAG (LOCKNAMESFLAG
, PCB
);
2761 CLEAR_FLAG (ONLYNAMESFLAG
, PCB
);
2764 case F_ToggleOnlyNames
:
2765 TOGGLE_FLAG (ONLYNAMESFLAG
, PCB
);
2766 CLEAR_FLAG (LOCKNAMESFLAG
, PCB
);
2769 case F_ToggleHideNames
:
2770 TOGGLE_FLAG (HIDENAMESFLAG
, PCB
);
2774 case F_ToggleShowDRC
:
2775 TOGGLE_FLAG (SHOWDRCFLAG
, PCB
);
2778 case F_ToggleLiveRoute
:
2779 TOGGLE_FLAG (LIVEROUTEFLAG
, PCB
);
2782 case F_ToggleAutoDRC
:
2783 notify_crosshair_change (false);
2784 TOGGLE_FLAG (AUTODRCFLAG
, PCB
);
2785 if (TEST_FLAG (AUTODRCFLAG
, PCB
) && Settings
.Mode
== LINE_MODE
)
2787 if (ClearFlagOnAllObjects (true, CONNECTEDFLAG
| FOUNDFLAG
))
2789 IncrementUndoSerialNumber ();
2792 if (Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
2794 LookupConnection (Crosshair
.AttachedLine
.Point1
.X
,
2795 Crosshair
.AttachedLine
.Point1
.Y
,
2796 true, 1, CONNECTEDFLAG
, false);
2797 LookupConnection (Crosshair
.AttachedLine
.Point1
.X
,
2798 Crosshair
.AttachedLine
.Point1
.Y
,
2799 true, 1, FOUNDFLAG
, true);
2802 notify_crosshair_change (true);
2805 case F_ToggleCheckPlanes
:
2806 TOGGLE_FLAG (CHECKPLANESFLAG
, PCB
);
2810 case F_ToggleOrthoMove
:
2811 TOGGLE_FLAG (ORTHOMOVEFLAG
, PCB
);
2815 TOGGLE_FLAG (SHOWNUMBERFLAG
, PCB
);
2820 TOGGLE_FLAG (SHOWMASKFLAG
, PCB
);
2824 case F_ToggleClearLine
:
2825 TOGGLE_FLAG (CLEARNEWFLAG
, PCB
);
2828 case F_ToggleFullPoly
:
2829 TOGGLE_FLAG (NEWFULLPOLYFLAG
, PCB
);
2832 /* shift grid alignment */
2835 Coord oldGrid
= PCB
->Grid
;
2838 if (MoveCrosshairAbsolute (Crosshair
.X
, Crosshair
.Y
))
2839 notify_crosshair_change (true); /* first notify was in MoveCrosshairAbs */
2840 SetGrid (oldGrid
, true);
2844 /* toggle displaying of the grid */
2846 Settings
.DrawGrid
= !Settings
.DrawGrid
;
2850 /* display the pinout of an element */
2853 ElementType
*element
;
2857 gui
->get_coords (_("Click on an element"), &x
, &y
);
2859 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
2860 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
2862 element
= (ElementType
*) ptrtmp
;
2863 gui
->show_item (element
);
2868 /* toggle displaying of pin/pad/via names */
2869 case F_PinOrPadName
:
2871 void *ptr1
, *ptr2
, *ptr3
;
2873 switch (SearchScreen (Crosshair
.X
, Crosshair
.Y
,
2874 ELEMENT_TYPE
| PIN_TYPE
| PAD_TYPE
|
2875 VIA_TYPE
, (void **) &ptr1
, (void **) &ptr2
,
2879 PIN_LOOP ((ElementType
*) ptr1
);
2881 if (TEST_FLAG (DISPLAYNAMEFLAG
, pin
))
2885 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, pin
, pin
);
2886 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pin
);
2889 PAD_LOOP ((ElementType
*) ptr1
);
2891 if (TEST_FLAG (DISPLAYNAMEFLAG
, pad
))
2895 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, pad
, pad
);
2896 TOGGLE_FLAG (DISPLAYNAMEFLAG
, pad
);
2899 SetChangedFlag (true);
2900 IncrementUndoSerialNumber ();
2905 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
))
2906 ErasePinName ((PinType
*) ptr2
);
2908 DrawPinName ((PinType
*) ptr2
);
2909 AddObjectToFlagUndoList (PIN_TYPE
, ptr1
, ptr2
, ptr3
);
2910 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
);
2911 SetChangedFlag (true);
2912 IncrementUndoSerialNumber ();
2917 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PadType
*) ptr2
))
2918 ErasePadName ((PadType
*) ptr2
);
2920 DrawPadName ((PadType
*) ptr2
);
2921 AddObjectToFlagUndoList (PAD_TYPE
, ptr1
, ptr2
, ptr3
);
2922 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PadType
*) ptr2
);
2923 SetChangedFlag (true);
2924 IncrementUndoSerialNumber ();
2928 if (TEST_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
))
2929 EraseViaName ((PinType
*) ptr2
);
2931 DrawViaName ((PinType
*) ptr2
);
2932 AddObjectToFlagUndoList (VIA_TYPE
, ptr1
, ptr2
, ptr3
);
2933 TOGGLE_FLAG (DISPLAYNAMEFLAG
, (PinType
*) ptr2
);
2934 SetChangedFlag (true);
2935 IncrementUndoSerialNumber ();
2945 else if (function
&& str_dir
)
2947 switch (GetFunctionID (function
))
2952 PCB
->GridOffsetX
= GetValue (argv
[1], NULL
, NULL
);
2953 PCB
->GridOffsetY
= GetValue (argv
[2], NULL
, NULL
);
2954 if (Settings
.DrawGrid
)
2973 /* --------------------------------------------------------------------------- */
2975 static const char mode_syntax
[] =
2976 N_("Mode(Arc|Arrow|Copy|InsertPoint|Line|Lock|Move|None|PasteBuffer)\n"
2977 "Mode(Polygon|Rectangle|Remove|Rotate|Text|Thermal|Via)\n"
2978 "Mode(Notify|Release|Cancel|Stroke)\n"
2979 "Mode(Save|Restore)");
2981 static const char mode_help
[] = N_("Change or use the tool mode.");
2983 /* %start-doc actions Mode
3003 Select the indicated tool.
3006 Called when you press the mouse button, or move the mouse.
3009 Called when you release the mouse button.
3012 Cancels any pending tool activity, allowing you to restart elsewhere.
3013 For example, this allows you to start a new line rather than attach a
3014 line to the previous line.
3017 Similar to Cancel but calling this action a second time will return
3021 If your @code{pcb} was built with libstroke, this invokes the stroke
3022 input method. If not, this will restart a drawing mode if you were
3023 drawing, else it will select objects.
3026 Remembers the current tool.
3029 Restores the tool to the last saved tool.
3036 ActionMode (int argc
, char **argv
, Coord x
, Coord y
)
3038 char *function
= ARG (0);
3042 Note
.X
= Crosshair
.X
;
3043 Note
.Y
= Crosshair
.Y
;
3044 notify_crosshair_change (false);
3045 switch (GetFunctionID (function
))
3051 SetMode (ARROW_MODE
);
3054 SetMode (COPY_MODE
);
3057 SetMode (INSERTPOINT_MODE
);
3060 SetMode (LINE_MODE
);
3063 SetMode (LOCK_MODE
);
3066 SetMode (MOVE_MODE
);
3073 int saved_mode
= Settings
.Mode
;
3075 SetMode (saved_mode
);
3080 switch (Settings
.Mode
)
3083 case PASTEBUFFER_MODE
:
3089 case INSERTPOINT_MODE
:
3090 case RUBBERBANDMOVE_MODE
:
3094 SetMode (ARROW_MODE
);
3098 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3099 SetMode (ARROW_MODE
);
3103 SetMode (LINE_MODE
);
3107 case RECTANGLE_MODE
:
3108 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3109 SetMode (ARROW_MODE
);
3113 SetMode (RECTANGLE_MODE
);
3118 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3119 SetMode (ARROW_MODE
);
3123 SetMode (POLYGON_MODE
);
3127 case POLYGONHOLE_MODE
:
3128 if (Crosshair
.AttachedLine
.State
== STATE_FIRST
)
3129 SetMode (ARROW_MODE
);
3133 SetMode (POLYGONHOLE_MODE
);
3138 if (Crosshair
.AttachedBox
.State
== STATE_FIRST
)
3139 SetMode (ARROW_MODE
);
3160 SetMode (PASTEBUFFER_MODE
);
3163 SetMode (POLYGON_MODE
);
3166 SetMode (POLYGONHOLE_MODE
);
3168 #ifndef HAVE_LIBSTROKE
3181 SetMode (REMOVE_MODE
);
3184 SetMode (RECTANGLE_MODE
);
3187 SetMode (ROTATE_MODE
);
3190 #ifdef HAVE_LIBSTROKE
3192 StrokeBox
.X1
= Crosshair
.X
;
3193 StrokeBox
.Y1
= Crosshair
.Y
;
3196 /* Handle middle mouse button restarts of drawing mode. If not in
3197 | a drawing mode, middle mouse button will select objects.
3199 if (Settings
.Mode
== LINE_MODE
3200 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3202 SetMode (LINE_MODE
);
3204 else if (Settings
.Mode
== ARC_MODE
3205 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3207 else if (Settings
.Mode
== RECTANGLE_MODE
3208 && Crosshair
.AttachedBox
.State
!= STATE_FIRST
)
3209 SetMode (RECTANGLE_MODE
);
3210 else if (Settings
.Mode
== POLYGON_MODE
3211 && Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
3212 SetMode (POLYGON_MODE
);
3217 SetMode (ARROW_MODE
);
3223 SetMode (TEXT_MODE
);
3226 SetMode (THERMAL_MODE
);
3232 case F_Restore
: /* restore the last saved mode */
3236 case F_Save
: /* save currently selected mode */
3240 notify_crosshair_change (true);
3247 /* --------------------------------------------------------------------------- */
3249 static const char removeselected_syntax
[] = N_("RemoveSelected()");
3251 static const char removeselected_help
[] = N_("Removes any selected objects.");
3253 /* %start-doc actions RemoveSelected
3258 ActionRemoveSelected (int argc
, char **argv
, Coord x
, Coord y
)
3260 if (RemoveSelected ())
3261 SetChangedFlag (true);
3265 /* --------------------------------------------------------------------------- */
3267 static const char renumber_syntax
[] = N_("Renumber()\n"
3268 "Renumber(filename)");
3270 static const char renumber_help
[] =
3271 N_("Renumber all elements. The changes will be recorded to filename\n"
3272 "for use in backannotating these changes to the schematic.");
3274 /* %start-doc actions Renumber
3279 ActionRenumber (int argc
, char **argv
, Coord x
, Coord y
)
3281 bool changed
= false;
3282 ElementType
**element_list
;
3283 ElementType
**locked_element_list
;
3284 unsigned int i
, j
, k
, cnt
, lock_cnt
;
3290 static char * default_file
= NULL
;
3291 size_t cnt_list_sz
= 100;
3297 char **was
, **is
, *pin
;
3298 unsigned int c_cnt
= 0;
3305 * We deal with the case where name already exists in this
3306 * function so the GUI doesn't need to deal with it
3308 name
= gui
->fileselect (_("Save Renumber Annotation File As ..."),
3309 _("Choose a file to record the renumbering to.\n"
3310 "This file may be used to back annotate the\n"
3311 "change to the schematics.\n"),
3312 default_file
, ".eco", "eco",
3322 free (default_file
);
3323 default_file
= NULL
;
3328 default_file
= strdup (name
);
3331 if ((out
= fopen (name
, "r")))
3334 if (!gui
->confirm_dialog (_("File exists! Ok to overwrite?"), 0))
3336 if (free_name
&& name
)
3342 if ((out
= fopen (name
, "w")) == NULL
)
3344 Message (_("Could not open %s\n"), name
);
3345 if (free_name
&& name
)
3350 if (free_name
&& name
)
3353 fprintf (out
, "*COMMENT* PCB Annotation File\n");
3354 fprintf (out
, "*FILEVERSION* 20061031\n");
3357 * Make a first pass through all of the elements and sort them out
3358 * by location on the board. While here we also collect a list of
3361 * We'll actually renumber things in the 2nd pass.
3363 element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementType
*));
3364 locked_element_list
= (ElementType
**)calloc (PCB
->Data
->ElementN
, sizeof (ElementType
*));
3365 was
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3366 is
= (char **)calloc (PCB
->Data
->ElementN
, sizeof (char *));
3367 if (element_list
== NULL
|| locked_element_list
== NULL
|| was
== NULL
3370 fprintf (stderr
, "calloc() failed in %s\n", __FUNCTION__
);
3377 ELEMENT_LOOP (PCB
->Data
);
3379 if (TEST_FLAG (LOCKFLAG
, element
->Name
) || TEST_FLAG (LOCKFLAG
, element
))
3382 * add to the list of locked elements which we won't try to
3383 * renumber and whose reference designators are now reserved.
3386 "*WARN* Element \"%s\" at %$md is locked and will not be renumbered.\n",
3387 UNKNOWN (NAMEONPCB_NAME (element
)), element
->MarkX
, element
->MarkY
);
3388 locked_element_list
[lock_cnt
] = element
;
3394 /* count of devices which will be renumbered */
3397 /* search for correct position in the list */
3399 while (element_list
[i
] && element
->MarkY
> element_list
[i
]->MarkY
)
3403 * We have found the position where we have the first element that
3404 * has the same Y value or a lower Y value. Now move forward if
3405 * needed through the X values
3407 while (element_list
[i
]
3408 && element
->MarkY
== element_list
[i
]->MarkY
3409 && element
->MarkX
> element_list
[i
]->MarkX
)
3412 for (j
= cnt
- 1; j
> i
; j
--)
3414 element_list
[j
] = element_list
[j
- 1];
3416 element_list
[i
] = element
;
3423 * Now that the elements are sorted by board position, we go through
3424 * and renumber them.
3428 * turn off the flag which requires unique names so it doesn't get
3429 * in our way. When we're done with the renumber we will have unique
3432 unique
= TEST_FLAG (UNIQUENAMEFLAG
, PCB
);
3433 CLEAR_FLAG (UNIQUENAMEFLAG
, PCB
);
3435 cnt_list
= (struct _cnt_list
*)calloc (cnt_list_sz
, sizeof (struct _cnt_list
));
3436 for (i
= 0; i
< cnt
; i
++)
3438 /* If there is no refdes, maybe just spit out a warning */
3439 if (NAMEONPCB_NAME (element_list
[i
]))
3441 /* figure out the prefix */
3442 tmps
= strdup (NAMEONPCB_NAME (element_list
[i
]));
3444 while (tmps
[j
] && (tmps
[j
] < '0' || tmps
[j
] > '9')
3449 /* check the counter for this prefix */
3451 cnt_list
[j
].name
&& (strcmp (cnt_list
[j
].name
, tmps
) != 0)
3452 && j
< cnt_list_sz
; j
++);
3454 /* grow the list if needed */
3455 if (j
== cnt_list_sz
)
3458 cnt_list
= (struct _cnt_list
*)realloc (cnt_list
, cnt_list_sz
);
3459 if (cnt_list
== NULL
)
3461 fprintf (stderr
, _("realloc failed() in %s\n"), __FUNCTION__
);
3464 /* zero out the memory that we added */
3465 for (tmpi
= j
; tmpi
< cnt_list_sz
; tmpi
++)
3467 cnt_list
[tmpi
].name
= NULL
;
3468 cnt_list
[tmpi
].cnt
= 0;
3473 * start a new counter if we don't have a counter for this
3476 if (!cnt_list
[j
].name
)
3478 cnt_list
[j
].name
= strdup (tmps
);
3479 cnt_list
[j
].cnt
= 0;
3483 * check to see if the new refdes is already used by a
3492 /* space for the prefix plus 1 digit plus the '\0' */
3493 sz
= strlen (cnt_list
[j
].name
) + 2;
3495 /* and 1 more per extra digit needed to hold the number */
3496 tmpi
= cnt_list
[j
].cnt
;
3502 tmps
= (char *)malloc (sz
* sizeof (char));
3503 sprintf (tmps
, "%s%d", cnt_list
[j
].name
, (int) cnt_list
[j
].cnt
);
3506 * now compare to the list of reserved (by locked
3509 for (k
= 0; k
< lock_cnt
; k
++)
3512 (UNKNOWN (NAMEONPCB_NAME (locked_element_list
[k
])),
3523 if (strcmp (tmps
, NAMEONPCB_NAME (element_list
[i
])) != 0)
3525 fprintf (out
, "*RENAME* \"%s\" \"%s\"\n",
3526 NAMEONPCB_NAME (element_list
[i
]), tmps
);
3528 /* add this rename to our table of renames so we can update the netlist */
3529 was
[c_cnt
] = strdup (NAMEONPCB_NAME (element_list
[i
]));
3530 is
[c_cnt
] = strdup (tmps
);
3533 AddObjectToChangeNameUndoList (ELEMENT_TYPE
, NULL
, NULL
,
3535 NAMEONPCB_NAME (element_list
3538 ChangeObjectName (ELEMENT_TYPE
, element_list
[i
], NULL
, NULL
,
3542 /* we don't free tmps in this case because it is used */
3549 pcb_fprintf (out
, "*WARN* Element at %$md has no name.\n",
3550 element_list
[i
]->MarkX
, element_list
[i
]->MarkY
);
3557 /* restore the unique flag setting */
3559 SET_FLAG (UNIQUENAMEFLAG
, PCB
);
3564 /* update the netlist */
3565 AddNetlistLibToUndoList (&(PCB
->NetlistLib
));
3567 /* iterate over each net */
3568 for (i
= 0; i
< PCB
->NetlistLib
.MenuN
; i
++)
3571 /* iterate over each pin on the net */
3572 for (j
= 0; j
< PCB
->NetlistLib
.Menu
[i
].EntryN
; j
++)
3575 /* figure out the pin number part from strings like U3-21 */
3576 tmps
= strdup (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3577 for (k
= 0; tmps
[k
] && tmps
[k
] != '-'; k
++);
3581 /* iterate over the list of changed reference designators */
3582 for (k
= 0; k
< c_cnt
; k
++)
3585 * if the pin needs to change, change it and quit
3586 * searching in the list.
3588 if (strcmp (tmps
, was
[k
]) == 0)
3590 free (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
);
3591 PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
=
3592 (char *)malloc ((strlen (is
[k
]) + strlen (pin
) +
3593 2) * sizeof (char));
3594 sprintf (PCB
->NetlistLib
.Menu
[i
].Entry
[j
].ListEntry
,
3595 "%s-%s", is
[k
], pin
);
3603 for (k
= 0; k
< c_cnt
; k
++)
3610 IncrementUndoSerialNumber ();
3611 SetChangedFlag (true);
3614 free (locked_element_list
);
3615 free (element_list
);
3623 /* --------------------------------------------------------------------------- */
3625 static const char ripup_syntax
[] = N_("RipUp(All|Selected|Element)");
3627 static const char ripup_help
[] =
3628 N_("Ripup auto-routed tracks, or convert an element to parts.");
3630 /* %start-doc actions RipUp
3635 Removes all lines and vias which were created by the autorouter.
3638 Removes all selected lines and vias which were created by the
3642 Converts the element under the cursor to parts (vias and lines). Note
3643 that this uses the highest numbered paste buffer.
3650 ActionRipUp (int argc
, char **argv
, Coord x
, Coord y
)
3652 char *function
= ARG (0);
3653 bool changed
= false;
3657 switch (GetFunctionID (function
))
3660 ALLLINE_LOOP (PCB
->Data
);
3662 if (TEST_FLAG (AUTOFLAG
, line
) && !TEST_FLAG (LOCKFLAG
, line
))
3664 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3669 ALLARC_LOOP (PCB
->Data
);
3671 if (TEST_FLAG (AUTOFLAG
, arc
) && !TEST_FLAG (LOCKFLAG
, arc
))
3673 RemoveObject (ARC_TYPE
, layer
, arc
, arc
);
3678 VIA_LOOP (PCB
->Data
);
3680 if (TEST_FLAG (AUTOFLAG
, via
) && !TEST_FLAG (LOCKFLAG
, via
))
3682 RemoveObject (VIA_TYPE
, via
, via
, via
);
3690 IncrementUndoSerialNumber ();
3691 SetChangedFlag (true);
3695 VISIBLELINE_LOOP (PCB
->Data
);
3697 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, line
)
3698 && !TEST_FLAG (LOCKFLAG
, line
))
3700 RemoveObject (LINE_TYPE
, layer
, line
, line
);
3706 VIA_LOOP (PCB
->Data
);
3708 if (TEST_FLAGS (AUTOFLAG
| SELECTEDFLAG
, via
)
3709 && !TEST_FLAG (LOCKFLAG
, via
))
3711 RemoveObject (VIA_TYPE
, via
, via
, via
);
3718 IncrementUndoSerialNumber ();
3719 SetChangedFlag (true);
3724 void *ptr1
, *ptr2
, *ptr3
;
3726 if (SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
3727 &ptr1
, &ptr2
, &ptr3
) != NO_TYPE
)
3729 Note
.Buffer
= Settings
.BufferNumber
;
3730 SetBufferNumber (MAX_BUFFER
- 1);
3731 ClearBuffer (PASTEBUFFER
);
3732 CopyObjectToBuffer (PASTEBUFFER
->Data
, PCB
->Data
,
3733 ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3734 SmashBufferElement (PASTEBUFFER
);
3737 SaveUndoSerialNumber ();
3738 EraseObject (ELEMENT_TYPE
, ptr1
, ptr1
);
3739 MoveObjectToRemoveUndoList (ELEMENT_TYPE
, ptr1
, ptr2
, ptr3
);
3740 RestoreUndoSerialNumber ();
3741 CopyPastebufferToLayout (0, 0);
3742 SetBufferNumber (Note
.Buffer
);
3743 SetChangedFlag (true);
3752 /* --------------------------------------------------------------------------- */
3754 static const char addrats_syntax
[] = N_("AddRats(AllRats|SelectedRats|Close)");
3756 static const char addrats_help
[] =
3757 N_("Add one or more rat lines to the board.");
3759 /* %start-doc actions AddRats
3764 Create rat lines for all loaded nets that aren't already connected on
3768 Similarly, but only add rat lines for nets connected to selected pins
3772 Selects the shortest unselected rat on the board.
3779 ActionAddRats (int argc
, char **argv
, Coord x
, Coord y
)
3781 char *function
= ARG (0);
3787 if (Settings
.RatWarn
)
3789 switch (GetFunctionID (function
))
3792 if (AddAllRats (false, NULL
))
3793 SetChangedFlag (true);
3795 case F_SelectedRats
:
3797 if (AddAllRats (true, NULL
))
3798 SetChangedFlag (true);
3801 small
= SQUARE (MAX_COORD
);
3803 RAT_LOOP (PCB
->Data
);
3805 if (TEST_FLAG (SELECTEDFLAG
, line
))
3807 len
= SQUARE (line
->Point1
.X
- line
->Point2
.X
) +
3808 SQUARE (line
->Point1
.Y
- line
->Point2
.Y
);
3818 AddObjectToFlagUndoList (RATLINE_TYPE
, shorty
, shorty
, shorty
);
3819 SET_FLAG (SELECTEDFLAG
, shorty
);
3822 CenterDisplay ((shorty
->Point2
.X
+ shorty
->Point1
.X
) / 2,
3823 (shorty
->Point2
.Y
+ shorty
->Point1
.Y
) / 2);
3831 /* --------------------------------------------------------------------------- */
3833 static const char delete_syntax
[] =
3834 N_("Delete(Object|Selected)\n"
3835 "Delete(AllRats|SelectedRats)");
3837 static const char delete_help
[] = N_("Delete stuff.");
3839 /* %start-doc actions Delete
3844 ActionDelete (int argc
, char **argv
, Coord x
, Coord y
)
3846 char *function
= ARG (0);
3847 int id
= GetFunctionID (function
);
3849 Note
.X
= Crosshair
.X
;
3850 Note
.Y
= Crosshair
.Y
;
3852 if (id
== -1) /* no arg */
3854 if (RemoveSelected() == false)
3862 SetMode(REMOVE_MODE
);
3870 if (DeleteRats (false))
3871 SetChangedFlag (true);
3873 case F_SelectedRats
:
3874 if (DeleteRats (true))
3875 SetChangedFlag (true);
3882 /* --------------------------------------------------------------------------- */
3884 static const char deleterats_syntax
[] =
3885 N_("DeleteRats(AllRats|Selected|SelectedRats)");
3887 static const char deleterats_help
[] = N_("Delete rat lines.");
3889 /* %start-doc actions DeleteRats
3894 ActionDeleteRats (int argc
, char **argv
, Coord x
, Coord y
)
3896 char *function
= ARG (0);
3899 if (Settings
.RatWarn
)
3901 switch (GetFunctionID (function
))
3904 if (DeleteRats (false))
3905 SetChangedFlag (true);
3907 case F_SelectedRats
:
3909 if (DeleteRats (true))
3910 SetChangedFlag (true);
3917 /* --------------------------------------------------------------------------- */
3919 static const char autoplace_syntax
[] = N_("AutoPlaceSelected()");
3921 static const char autoplace_help
[] = N_("Auto-place selected components.");
3923 /* %start-doc actions AutoPlaceSelected
3925 Attempts to re-arrange the selected components such that the nets
3926 connecting them are minimized. Note that you cannot undo this.
3931 ActionAutoPlaceSelected (int argc
, char **argv
, Coord x
, Coord y
)
3934 if (gui
->confirm_dialog (_("Auto-placement can NOT be undone.\n"
3935 "Do you want to continue anyway?\n"), 0))
3937 if (AutoPlaceSelected ())
3938 SetChangedFlag (true);
3943 /* --------------------------------------------------------------------------- */
3945 static const char autoroute_syntax
[] = N_("AutoRoute(AllRats|SelectedRats)");
3947 static const char autoroute_help
[] = N_("Auto-route some or all rat lines.");
3949 /* %start-doc actions AutoRoute
3954 Attempt to autoroute all rats.
3957 Attempt to autoroute the selected rats.
3961 Before autorouting, it's important to set up a few things. First,
3962 make sure any layers you aren't using are disabled, else the
3963 autorouter may use them. Next, make sure the current line and via
3964 styles are set accordingly. Last, make sure "new lines clear
3965 polygons" is set, in case you eventually want to add a copper pour.
3967 Autorouting takes a while. During this time, the program may not be
3973 ActionAutoRoute (int argc
, char **argv
, Coord x
, Coord y
)
3975 char *function
= ARG (0);
3977 if (function
) /* one parameter */
3979 switch (GetFunctionID (function
))
3982 if (AutoRoute (false))
3983 SetChangedFlag (true);
3985 case F_SelectedRats
:
3987 if (AutoRoute (true))
3988 SetChangedFlag (true);
3995 /* --------------------------------------------------------------------------- */
3997 static const char markcrosshair_syntax
[] =
3998 N_("MarkCrosshair()\n"
3999 "MarkCrosshair(Center)");
4001 static const char markcrosshair_help
[] = N_("Set/Reset the Crosshair mark.");
4003 /* %start-doc actions MarkCrosshair
4005 The ``mark'' is a small X-shaped target on the display which is
4006 treated like a second origin (the normal origin is the upper let
4007 corner of the board). The GUI will display a second set of
4008 coordinates for this mark, which tells you how far you are from it.
4010 If no argument is given, the mark is toggled - disabled if it was
4011 enabled, or enabled at the current cursor position of disabled. If
4012 the @code{Center} argument is given, the mark is moved to the current
4018 ActionMarkCrosshair (int argc
, char **argv
, Coord x
, Coord y
)
4020 char *function
= ARG (0);
4021 if (!function
|| !*function
)
4025 notify_mark_change (false);
4026 Marked
.status
= false;
4027 notify_mark_change (true);
4031 notify_mark_change (false);
4032 Marked
.status
= false;
4033 Marked
.status
= true;
4034 Marked
.X
= Crosshair
.X
;
4035 Marked
.Y
= Crosshair
.Y
;
4036 notify_mark_change (true);
4039 else if (GetFunctionID (function
) == F_Center
)
4041 notify_mark_change (false);
4042 Marked
.status
= true;
4043 Marked
.X
= Crosshair
.X
;
4044 Marked
.Y
= Crosshair
.Y
;
4045 notify_mark_change (true);
4050 /* --------------------------------------------------------------------------- */
4052 static const char changesize_syntax
[] =
4053 N_("ChangeSize(Object, delta)\n"
4054 "ChangeSize(SelectedObjects|Selected, delta)\n"
4055 "ChangeSize(SelectedLines|SelectedPins|SelectedVias, delta)\n"
4056 "ChangeSize(SelectedPads|SelectedTexts|SelectedNames, delta)\n"
4057 "ChangeSize(SelectedElements, delta)");
4059 static const char changesize_help
[] = N_("Changes the size of objects.");
4061 /* %start-doc actions ChangeSize
4063 For lines and arcs, this changes the width. For pins and vias, this
4064 changes the overall diameter of the copper annulus. For pads, this
4065 changes the width and, indirectly, the length. For texts and names,
4066 this changes the scaling factor. For elements, this changes the width
4067 of the silk layer lines and arcs for this element.
4072 ActionChangeSize (int argc
, char **argv
, Coord x
, Coord y
)
4074 char *function
= ARG (0);
4075 char *delta
= ARG (1);
4076 char *units
= ARG (2);
4077 bool absolute
; /* indicates if absolute size is given */
4080 if (function
&& delta
)
4082 value
= GetValue (delta
, units
, &absolute
);
4084 value
= delta
[0] == '-' ? -Settings
.increments
->size
4085 : Settings
.increments
->size
;
4086 switch (GetFunctionID (function
))
4091 void *ptr1
, *ptr2
, *ptr3
;
4094 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
4095 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4096 if (TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
4097 Message (_("Sorry, the object is locked\n"));
4098 if (ChangeObjectSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4099 SetChangedFlag (true);
4103 case F_SelectedVias
:
4104 if (ChangeSelectedSize (VIA_TYPE
, value
, absolute
))
4105 SetChangedFlag (true);
4108 case F_SelectedPins
:
4109 if (ChangeSelectedSize (PIN_TYPE
, value
, absolute
))
4110 SetChangedFlag (true);
4113 case F_SelectedPads
:
4114 if (ChangeSelectedSize (PAD_TYPE
, value
, absolute
))
4115 SetChangedFlag (true);
4118 case F_SelectedArcs
:
4119 if (ChangeSelectedSize (ARC_TYPE
, value
, absolute
))
4120 SetChangedFlag (true);
4123 case F_SelectedLines
:
4124 if (ChangeSelectedSize (LINE_TYPE
, value
, absolute
))
4125 SetChangedFlag (true);
4128 case F_SelectedTexts
:
4129 if (ChangeSelectedSize (TEXT_TYPE
, value
, absolute
))
4130 SetChangedFlag (true);
4133 case F_SelectedNames
:
4134 if (ChangeSelectedSize (ELEMENTNAME_TYPE
, value
, absolute
))
4135 SetChangedFlag (true);
4138 case F_SelectedElements
:
4139 if (ChangeSelectedSize (ELEMENT_TYPE
, value
, absolute
))
4140 SetChangedFlag (true);
4144 case F_SelectedObjects
:
4145 if (ChangeSelectedSize (CHANGESIZE_TYPES
, value
, absolute
))
4146 SetChangedFlag (true);
4153 /* --------------------------------------------------------------------------- */
4155 static const char changedrillsize_syntax
[] =
4156 N_("ChangeDrillSize(Object, delta)\n"
4157 "ChangeDrillSize(SelectedPins|SelectedVias|Selected|SelectedObjects, delta)");
4159 static const char changedrillsize_help
[] =
4160 N_("Changes the drilling hole size of objects.");
4162 /* %start-doc actions ChangeDrillSize
4167 ActionChange2ndSize (int argc
, char **argv
, Coord x
, Coord y
)
4169 char *function
= ARG (0);
4170 char *delta
= ARG (1);
4171 char *units
= ARG (2);
4175 if (function
&& delta
)
4177 value
= GetValue (delta
, units
, &absolute
);
4178 switch (GetFunctionID (function
))
4183 void *ptr1
, *ptr2
, *ptr3
;
4185 gui
->get_coords (_("Select an Object"), &x
, &y
);
4187 SearchScreen (x
, y
, CHANGE2NDSIZE_TYPES
,
4188 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4189 if (ChangeObject2ndSize
4190 (type
, ptr1
, ptr2
, ptr3
, value
, absolute
, true))
4191 SetChangedFlag (true);
4195 case F_SelectedVias
:
4196 if (ChangeSelected2ndSize (VIA_TYPE
, value
, absolute
))
4197 SetChangedFlag (true);
4200 case F_SelectedPins
:
4201 if (ChangeSelected2ndSize (PIN_TYPE
, value
, absolute
))
4202 SetChangedFlag (true);
4205 case F_SelectedObjects
:
4206 if (ChangeSelected2ndSize (PIN_TYPES
, value
, absolute
))
4207 SetChangedFlag (true);
4214 /* --------------------------------------------------------------------------- */
4216 static const char changeclearsize_syntax
[] =
4217 N_("ChangeClearSize(Object, delta)\n"
4218 "ChangeClearSize(SelectedPins|SelectedPads|SelectedVias, delta)\n"
4219 "ChangeClearSize(SelectedLines|SelectedArcs, delta\n"
4220 "ChangeClearSize(Selected|SelectedObjects, delta)");
4222 static const char changeclearsize_help
[] =
4223 N_("Changes the clearance size of objects.");
4225 /* %start-doc actions ChangeClearSize
4227 If the solder mask is currently showing, this action changes the
4228 solder mask clearance. If the mask is not showing, this action
4229 changes the polygon clearance.
4234 ActionChangeClearSize (int argc
, char **argv
, Coord x
, Coord y
)
4236 char *function
= ARG (0);
4237 char *delta
= ARG (1);
4238 char *units
= ARG (2);
4242 if (function
&& delta
)
4244 value
= 2 * GetValue (delta
, units
, &absolute
);
4246 value
= delta
[0] == '-' ? -Settings
.increments
->clear
4247 : Settings
.increments
->clear
;
4248 switch (GetFunctionID (function
))
4253 void *ptr1
, *ptr2
, *ptr3
;
4255 gui
->get_coords (_("Select an Object"), &x
, &y
);
4258 CHANGECLEARSIZE_TYPES
, &ptr1
, &ptr2
,
4260 if (ChangeObjectClearSize (type
, ptr1
, ptr2
, ptr3
, value
, absolute
))
4261 SetChangedFlag (true);
4264 case F_SelectedVias
:
4265 if (ChangeSelectedClearSize (VIA_TYPE
, value
, absolute
))
4266 SetChangedFlag (true);
4268 case F_SelectedPads
:
4269 if (ChangeSelectedClearSize (PAD_TYPE
, value
, absolute
))
4270 SetChangedFlag (true);
4272 case F_SelectedPins
:
4273 if (ChangeSelectedClearSize (PIN_TYPE
, value
, absolute
))
4274 SetChangedFlag (true);
4276 case F_SelectedLines
:
4277 if (ChangeSelectedClearSize (LINE_TYPE
, value
, absolute
))
4278 SetChangedFlag (true);
4280 case F_SelectedArcs
:
4281 if (ChangeSelectedClearSize (ARC_TYPE
, value
, absolute
))
4282 SetChangedFlag (true);
4285 case F_SelectedObjects
:
4286 if (ChangeSelectedClearSize (CHANGECLEARSIZE_TYPES
, value
, absolute
))
4287 SetChangedFlag (true);
4294 /* --------------------------------------------------------------------------- */
4296 static const char minmaskgap_syntax
[] =
4297 N_("MinMaskGap(delta)\n"
4298 "MinMaskGap(Selected, delta)");
4300 static const char minmaskgap_help
[] =
4301 N_("Ensures the mask is a minimum distance from pins and pads.");
4303 /* %start-doc actions MinMaskGap
4305 Checks all specified pins and/or pads, and increases the mask if
4306 needed to ensure a minimum distance between the pin or pad edge and
4312 ActionMinMaskGap (int argc
, char **argv
, Coord x
, Coord y
)
4314 char *function
= ARG (0);
4315 char *delta
= ARG (1);
4316 char *units
= ARG (2);
4324 if (strcasecmp (function
, "Selected") == 0)
4325 flags
= SELECTEDFLAG
;
4332 value
= 2 * GetValue (delta
, units
, &absolute
);
4334 SaveUndoSerialNumber ();
4335 ELEMENT_LOOP (PCB
->Data
);
4339 if (!TEST_FLAGS (flags
, pin
) || ! pin
->Mask
)
4342 thickness
= pin
->DrillingHole
;
4343 if (pin
->Thickness
> thickness
)
4344 thickness
= pin
->Thickness
;
4347 if (pin
->Mask
< thickness
)
4349 ChangeObjectMaskSize (PIN_TYPE
, element
, pin
, 0, thickness
, 1);
4350 RestoreUndoSerialNumber ();
4356 if (!TEST_FLAGS (flags
, pad
) || ! pad
->Mask
)
4358 if (pad
->Mask
< pad
->Thickness
+ value
)
4360 ChangeObjectMaskSize (PAD_TYPE
, element
, pad
, 0,
4361 pad
->Thickness
+ value
, 1);
4362 RestoreUndoSerialNumber ();
4368 VIA_LOOP (PCB
->Data
);
4370 if (!TEST_FLAGS (flags
, via
) || ! via
->Mask
)
4373 thickness
= via
->DrillingHole
;
4374 if (via
->Thickness
> thickness
)
4375 thickness
= via
->Thickness
;
4378 if (via
->Mask
< thickness
)
4380 ChangeObjectMaskSize (VIA_TYPE
, via
, 0, 0, thickness
, 1);
4381 RestoreUndoSerialNumber ();
4385 RestoreUndoSerialNumber ();
4386 IncrementUndoSerialNumber ();
4390 /* --------------------------------------------------------------------------- */
4392 static const char mincleargap_syntax
[] =
4393 N_("MinClearGap(delta)\n"
4394 "MinClearGap(Selected, delta)");
4396 static const char mincleargap_help
[] =
4397 N_("Ensures that polygons are a minimum distance from objects.");
4399 /* %start-doc actions MinClearGap
4401 Checks all specified objects, and increases the polygon clearance if
4402 needed to ensure a minimum distance between their edges and the
4408 ActionMinClearGap (int argc
, char **argv
, Coord x
, Coord y
)
4410 char *function
= ARG (0);
4411 char *delta
= ARG (1);
4412 char *units
= ARG (2);
4419 if (strcasecmp (function
, "Selected") == 0)
4420 flags
= SELECTEDFLAG
;
4427 value
= 2 * GetValue (delta
, units
, &absolute
);
4429 SaveUndoSerialNumber ();
4430 ELEMENT_LOOP (PCB
->Data
);
4434 if (!TEST_FLAGS (flags
, pin
))
4436 if (pin
->Clearance
< value
)
4438 ChangeObjectClearSize (PIN_TYPE
, element
, pin
, 0,
4440 RestoreUndoSerialNumber ();
4446 if (!TEST_FLAGS (flags
, pad
))
4448 if (pad
->Clearance
< value
)
4450 ChangeObjectClearSize (PAD_TYPE
, element
, pad
, 0,
4452 RestoreUndoSerialNumber ();
4458 VIA_LOOP (PCB
->Data
);
4460 if (!TEST_FLAGS (flags
, via
))
4462 if (via
->Clearance
< value
)
4464 ChangeObjectClearSize (VIA_TYPE
, via
, 0, 0, value
, 1);
4465 RestoreUndoSerialNumber ();
4469 ALLLINE_LOOP (PCB
->Data
);
4471 if (!TEST_FLAGS (flags
, line
))
4473 if (line
->Clearance
< value
)
4475 ChangeObjectClearSize (LINE_TYPE
, layer
, line
, 0, value
, 1);
4476 RestoreUndoSerialNumber ();
4480 ALLARC_LOOP (PCB
->Data
);
4482 if (!TEST_FLAGS (flags
, arc
))
4484 if (arc
->Clearance
< value
)
4486 ChangeObjectClearSize (ARC_TYPE
, layer
, arc
, 0, value
, 1);
4487 RestoreUndoSerialNumber ();
4491 RestoreUndoSerialNumber ();
4492 IncrementUndoSerialNumber ();
4496 /* --------------------------------------------------------------------------- */
4498 static const char changepinname_syntax
[] =
4499 N_("ChangePinName(ElementName,PinNumber,PinName)");
4501 static const char changepinname_help
[] =
4502 N_("Sets the name of a specific pin on a specific element.");
4504 /* %start-doc actions ChangePinName
4506 This can be especially useful for annotating pin names from a
4507 schematic to the layout without requiring knowledge of the pcb file
4511 ChangePinName(U3, 7, VCC)
4517 ActionChangePinName (int argc
, char **argv
, Coord x
, Coord y
)
4520 char *refdes
, *pinnum
, *pinname
;
4524 AFAIL (changepinname
);
4531 ELEMENT_LOOP (PCB
->Data
);
4533 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
4537 if (NSTRCMP (pinnum
, pin
->Number
) == 0)
4539 AddObjectToChangeNameUndoList (PIN_TYPE
, NULL
, NULL
,
4542 * Note: we can't free() pin->Name first because
4543 * it is used in the undo list
4545 pin
->Name
= strdup (pinname
);
4546 SetChangedFlag (true);
4554 if (NSTRCMP (pinnum
, pad
->Number
) == 0)
4556 AddObjectToChangeNameUndoList (PAD_TYPE
, NULL
, NULL
,
4559 * Note: we can't free() pad->Name first because
4560 * it is used in the undo list
4562 pad
->Name
= strdup (pinname
);
4563 SetChangedFlag (true);
4572 * done with our action so increment the undo # if we actually
4578 defer_needs_update
= 1;
4581 IncrementUndoSerialNumber ();
4582 gui
->invalidate_all ();
4589 /* --------------------------------------------------------------------------- */
4591 static const char changename_syntax
[] =
4592 N_("ChangeName(Object)\n"
4593 "ChangeName(Layout|Layer)");
4595 static const char changename_help
[] = N_("Sets the name of objects.");
4597 /* %start-doc actions ChangeName
4602 Changes the name of the element under the cursor.
4605 Changes the name of the layout. This is printed on the fab drawings.
4608 Changes the name of the currently active layer.
4615 ActionChangeName (int argc
, char **argv
, Coord x
, Coord y
)
4617 char *function
= ARG (0);
4622 switch (GetFunctionID (function
))
4624 /* change the name of an object */
4628 void *ptr1
, *ptr2
, *ptr3
;
4630 gui
->get_coords (_("Select an Object"), &x
, &y
);
4632 SearchScreen (x
, y
, CHANGENAME_TYPES
,
4633 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4635 SaveUndoSerialNumber ();
4636 if (QueryInputAndChangeObjectName (type
, ptr1
, ptr2
, ptr3
))
4638 SetChangedFlag (true);
4639 if (type
== ELEMENT_TYPE
)
4641 RubberbandType
*ptr
;
4644 RestoreUndoSerialNumber ();
4645 Crosshair
.AttachedObject
.RubberbandN
= 0;
4646 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
4647 ptr
= Crosshair
.AttachedObject
.Rubberband
;
4648 for (i
= 0; i
< Crosshair
.AttachedObject
.RubberbandN
;
4652 EraseRat ((RatType
*) ptr
->Line
);
4653 MoveObjectToRemoveUndoList (RATLINE_TYPE
,
4654 ptr
->Line
, ptr
->Line
,
4657 IncrementUndoSerialNumber ();
4665 /* change the layout's name */
4668 gui
->prompt_for (_("Enter the layout name:"), EMPTY (PCB
->Name
));
4669 /* NB: ChangeLayoutName takes ownership of the passed memory */
4670 if (name
&& ChangeLayoutName (name
))
4671 SetChangedFlag (true);
4674 /* change the name of the active layer */
4676 name
= gui
->prompt_for (_("Enter the layer name:"),
4677 EMPTY (CURRENT
->Name
));
4678 /* NB: ChangeLayerName takes ownership of the passed memory */
4679 if (name
&& ChangeLayerName (CURRENT
, name
))
4680 SetChangedFlag (true);
4688 /* --------------------------------------------------------------------------- */
4690 static const char morphpolygon_syntax
[] = N_("MorphPolygon(Object|Selected)");
4692 static const char morphpolygon_help
[] =
4693 N_("Converts dead polygon islands into separate polygons.");
4695 /* %start-doc actions MorphPolygon
4697 If a polygon is divided into unconnected "islands", you can use
4698 this command to convert the otherwise disappeared islands into
4699 separate polygons. Be sure the cursor is over a portion of the
4700 polygon that remains visible. Very small islands that may flake
4701 off are automatically deleted.
4706 ActionMorphPolygon (int argc
, char **argv
, Coord x
, Coord y
)
4708 char *function
= ARG (0);
4711 switch (GetFunctionID (function
))
4716 void *ptr1
, *ptr2
, *ptr3
;
4718 gui
->get_coords (_("Select an Object"), &x
, &y
);
4719 if ((type
= SearchScreen (x
, y
, POLYGON_TYPE
,
4720 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4722 MorphPolygon ((LayerType
*) ptr1
, (PolygonType
*) ptr3
);
4724 IncrementUndoSerialNumber ();
4729 case F_SelectedObjects
:
4730 ALLPOLYGON_LOOP (PCB
->Data
);
4732 if (TEST_FLAG (SELECTEDFLAG
, polygon
))
4733 MorphPolygon (layer
, polygon
);
4737 IncrementUndoSerialNumber ();
4744 /* --------------------------------------------------------------------------- */
4746 static const char togglehidename_syntax
[] =
4747 N_("ToggleHideName(Object|SelectedElements)");
4749 static const char togglehidename_help
[] =
4750 N_("Toggles the visibility of element names.");
4752 /* %start-doc actions ToggleHideName
4754 If names are hidden you won't see them on the screen and they will not
4755 appear on the silk layer when you print the layout.
4760 ActionToggleHideName (int argc
, char **argv
, Coord x
, Coord y
)
4762 char *function
= ARG (0);
4763 if (function
&& PCB
->ElementOn
)
4765 switch (GetFunctionID (function
))
4770 void *ptr1
, *ptr2
, *ptr3
;
4772 gui
->get_coords (_("Select an Object"), &x
, &y
);
4773 if ((type
= SearchScreen (x
, y
, ELEMENT_TYPE
,
4774 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4776 AddObjectToFlagUndoList (type
, ptr1
, ptr2
, ptr3
);
4777 EraseElementName ((ElementType
*) ptr2
);
4778 TOGGLE_FLAG (HIDENAMEFLAG
, (ElementType
*) ptr2
);
4779 DrawElementName ((ElementType
*) ptr2
);
4781 IncrementUndoSerialNumber ();
4785 case F_SelectedElements
:
4788 bool changed
= false;
4789 ELEMENT_LOOP (PCB
->Data
);
4791 if ((TEST_FLAG (SELECTEDFLAG
, element
) ||
4792 TEST_FLAG (SELECTEDFLAG
,
4793 &NAMEONPCB_TEXT (element
)))
4794 && (FRONT (element
) || PCB
->InvisibleObjectsOn
))
4796 AddObjectToFlagUndoList (ELEMENT_TYPE
, element
,
4798 EraseElementName (element
);
4799 TOGGLE_FLAG (HIDENAMEFLAG
, element
);
4800 DrawElementName (element
);
4808 IncrementUndoSerialNumber ();
4816 /* --------------------------------------------------------------------------- */
4818 static const char changejoin_syntax
[] =
4819 N_("ChangeJoin(ToggleObject|SelectedLines|SelectedArcs|Selected)");
4821 static const char changejoin_help
[] =
4822 N_("Changes the join (clearance through polygons) of objects.");
4824 /* %start-doc actions ChangeJoin
4826 The join flag determines whether a line or arc, drawn to intersect a
4827 polygon, electrically connects to the polygon or not. When joined,
4828 the line/arc is simply drawn over the polygon, making an electrical
4829 connection. When not joined, a gap is drawn between the line and the
4830 polygon, insulating them from each other.
4835 ActionChangeJoin (int argc
, char **argv
, Coord x
, Coord y
)
4837 char *function
= ARG (0);
4840 switch (GetFunctionID (function
))
4842 case F_ToggleObject
:
4846 void *ptr1
, *ptr2
, *ptr3
;
4848 gui
->get_coords (_("Select an Object"), &x
, &y
);
4850 SearchScreen (x
, y
, CHANGEJOIN_TYPES
,
4851 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4852 if (ChangeObjectJoin (type
, ptr1
, ptr2
, ptr3
))
4853 SetChangedFlag (true);
4857 case F_SelectedLines
:
4858 if (ChangeSelectedJoin (LINE_TYPE
))
4859 SetChangedFlag (true);
4862 case F_SelectedArcs
:
4863 if (ChangeSelectedJoin (ARC_TYPE
))
4864 SetChangedFlag (true);
4868 case F_SelectedObjects
:
4869 if (ChangeSelectedJoin (CHANGEJOIN_TYPES
))
4870 SetChangedFlag (true);
4877 /* --------------------------------------------------------------------------- */
4879 static const char changesquare_syntax
[] =
4880 N_("ChangeSquare(ToggleObject)\n"
4881 "ChangeSquare(SelectedElements|SelectedPins)\n"
4882 "ChangeSquare(Selected|SelectedObjects)");
4884 static const char changesquare_help
[] =
4885 N_("Changes the square flag of pins and pads.");
4887 /* %start-doc actions ChangeSquare
4889 Note that @code{Pins} means both pins and pads.
4896 ActionChangeSquare (int argc
, char **argv
, Coord x
, Coord y
)
4898 char *function
= ARG (0);
4901 switch (GetFunctionID (function
))
4903 case F_ToggleObject
:
4907 void *ptr1
, *ptr2
, *ptr3
;
4909 gui
->get_coords (_("Select an Object"), &x
, &y
);
4911 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4912 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4913 if (ChangeObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4914 SetChangedFlag (true);
4918 case F_SelectedElements
:
4919 if (ChangeSelectedSquare (ELEMENT_TYPE
))
4920 SetChangedFlag (true);
4923 case F_SelectedPins
:
4924 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4925 SetChangedFlag (true);
4929 case F_SelectedObjects
:
4930 if (ChangeSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4931 SetChangedFlag (true);
4938 /* --------------------------------------------------------------------------- */
4940 static const char setsquare_syntax
[] =
4941 N_("SetSquare(ToggleObject|SelectedElements|SelectedPins)");
4943 static const char setsquare_help
[] = N_("sets the square-flag of objects.");
4945 /* %start-doc actions SetSquare
4947 Note that @code{Pins} means pins and pads.
4954 ActionSetSquare (int argc
, char **argv
, Coord x
, Coord y
)
4956 char *function
= ARG (0);
4957 if (function
&& *function
)
4959 switch (GetFunctionID (function
))
4961 case F_ToggleObject
:
4965 void *ptr1
, *ptr2
, *ptr3
;
4967 gui
->get_coords (_("Select an Object"), &x
, &y
);
4969 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
4970 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
4971 if (SetObjectSquare (type
, ptr1
, ptr2
, ptr3
))
4972 SetChangedFlag (true);
4976 case F_SelectedElements
:
4977 if (SetSelectedSquare (ELEMENT_TYPE
))
4978 SetChangedFlag (true);
4981 case F_SelectedPins
:
4982 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4983 SetChangedFlag (true);
4987 case F_SelectedObjects
:
4988 if (SetSelectedSquare (PIN_TYPE
| PAD_TYPE
))
4989 SetChangedFlag (true);
4996 /* --------------------------------------------------------------------------- */
4998 static const char clearsquare_syntax
[] =
4999 N_("ClearSquare(ToggleObject|SelectedElements|SelectedPins)");
5001 static const char clearsquare_help
[] =
5002 N_("Clears the square-flag of pins and pads.");
5004 /* %start-doc actions ClearSquare
5006 Note that @code{Pins} means pins and pads.
5013 ActionClearSquare (int argc
, char **argv
, Coord x
, Coord y
)
5015 char *function
= ARG (0);
5016 if (function
&& *function
)
5018 switch (GetFunctionID (function
))
5020 case F_ToggleObject
:
5024 void *ptr1
, *ptr2
, *ptr3
;
5026 gui
->get_coords (_("Select an Object"), &x
, &y
);
5028 SearchScreen (x
, y
, CHANGESQUARE_TYPES
,
5029 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5030 if (ClrObjectSquare (type
, ptr1
, ptr2
, ptr3
))
5031 SetChangedFlag (true);
5035 case F_SelectedElements
:
5036 if (ClrSelectedSquare (ELEMENT_TYPE
))
5037 SetChangedFlag (true);
5040 case F_SelectedPins
:
5041 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
5042 SetChangedFlag (true);
5046 case F_SelectedObjects
:
5047 if (ClrSelectedSquare (PIN_TYPE
| PAD_TYPE
))
5048 SetChangedFlag (true);
5055 /* --------------------------------------------------------------------------- */
5057 static const char changeoctagon_syntax
[] =
5058 N_("ChangeOctagon(Object|ToggleObject|SelectedObjects|Selected)\n"
5059 "ChangeOctagon(SelectedElements|SelectedPins|SelectedVias)");
5061 static const char changeoctagon_help
[] =
5062 N_("Changes the octagon-flag of pins and vias.");
5064 /* %start-doc actions ChangeOctagon
5071 ActionChangeOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5073 char *function
= ARG (0);
5076 switch (GetFunctionID (function
))
5078 case F_ToggleObject
:
5082 void *ptr1
, *ptr2
, *ptr3
;
5084 gui
->get_coords (_("Select an Object"), &x
, &y
);
5086 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5087 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5088 if (ChangeObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5089 SetChangedFlag (true);
5093 case F_SelectedElements
:
5094 if (ChangeSelectedOctagon (ELEMENT_TYPE
))
5095 SetChangedFlag (true);
5098 case F_SelectedPins
:
5099 if (ChangeSelectedOctagon (PIN_TYPE
))
5100 SetChangedFlag (true);
5103 case F_SelectedVias
:
5104 if (ChangeSelectedOctagon (VIA_TYPE
))
5105 SetChangedFlag (true);
5109 case F_SelectedObjects
:
5110 if (ChangeSelectedOctagon (PIN_TYPES
))
5111 SetChangedFlag (true);
5118 /* --------------------------------------------------------------------------- */
5120 static const char setoctagon_syntax
[] =
5121 N_("SetOctagon(Object|ToggleObject|SelectedElements|Selected)");
5123 static const char setoctagon_help
[] = N_("Sets the octagon-flag of objects.");
5125 /* %start-doc actions SetOctagon
5132 ActionSetOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5134 char *function
= ARG (0);
5137 switch (GetFunctionID (function
))
5139 case F_ToggleObject
:
5143 void *ptr1
, *ptr2
, *ptr3
;
5145 gui
->get_coords (_("Select an Object"), &x
, &y
);
5147 SearchScreen (x
, y
, CHANGEOCTAGON_TYPES
,
5148 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5149 if (SetObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5150 SetChangedFlag (true);
5154 case F_SelectedElements
:
5155 if (SetSelectedOctagon (ELEMENT_TYPE
))
5156 SetChangedFlag (true);
5159 case F_SelectedPins
:
5160 if (SetSelectedOctagon (PIN_TYPE
))
5161 SetChangedFlag (true);
5164 case F_SelectedVias
:
5165 if (SetSelectedOctagon (VIA_TYPE
))
5166 SetChangedFlag (true);
5170 case F_SelectedObjects
:
5171 if (SetSelectedOctagon (PIN_TYPES
))
5172 SetChangedFlag (true);
5179 /* --------------------------------------------------------------------------- */
5181 static const char clearoctagon_syntax
[] =
5182 N_("ClearOctagon(ToggleObject|Object|SelectedObjects|Selected)\n"
5183 "ClearOctagon(SelectedElements|SelectedPins|SelectedVias)");
5185 static const char clearoctagon_help
[] =
5186 N_("Clears the octagon-flag of pins and vias.");
5188 /* %start-doc actions ClearOctagon
5195 ActionClearOctagon (int argc
, char **argv
, Coord x
, Coord y
)
5197 char *function
= ARG (0);
5200 switch (GetFunctionID (function
))
5202 case F_ToggleObject
:
5206 void *ptr1
, *ptr2
, *ptr3
;
5208 gui
->get_coords (_("Select an Object"), &x
, &y
);
5210 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGEOCTAGON_TYPES
,
5211 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
5212 if (ClrObjectOctagon (type
, ptr1
, ptr2
, ptr3
))
5213 SetChangedFlag (true);
5217 case F_SelectedElements
:
5218 if (ClrSelectedOctagon (ELEMENT_TYPE
))
5219 SetChangedFlag (true);
5222 case F_SelectedPins
:
5223 if (ClrSelectedOctagon (PIN_TYPE
))
5224 SetChangedFlag (true);
5227 case F_SelectedVias
:
5228 if (ClrSelectedOctagon (VIA_TYPE
))
5229 SetChangedFlag (true);
5233 case F_SelectedObjects
:
5234 if (ClrSelectedOctagon (PIN_TYPES
))
5235 SetChangedFlag (true);
5242 /* --------------------------------------------------------------------------- */
5244 static const char changehold_syntax
[] =
5245 N_("ChangeHole(ToggleObject|Object|SelectedVias|Selected)");
5247 static const char changehold_help
[] = N_("Changes the hole flag of objects.");
5249 /* %start-doc actions ChangeHole
5251 The "hole flag" of a via determines whether the via is a
5252 plated-through hole (not set), or an unplated hole (set).
5257 ActionChangeHole (int argc
, char **argv
, Coord x
, Coord y
)
5259 char *function
= ARG (0);
5262 switch (GetFunctionID (function
))
5264 case F_ToggleObject
:
5268 void *ptr1
, *ptr2
, *ptr3
;
5270 gui
->get_coords (_("Select an Object"), &x
, &y
);
5271 if ((type
= SearchScreen (x
, y
, VIA_TYPE
,
5272 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5273 && ChangeHole ((PinType
*) ptr3
))
5274 IncrementUndoSerialNumber ();
5278 case F_SelectedVias
:
5280 if (ChangeSelectedHole ())
5281 SetChangedFlag (true);
5288 /* --------------------------------------------------------------------------- */
5290 static const char changepaste_syntax
[] =
5291 N_("ChangePaste(ToggleObject|Object|SelectedPads|Selected)");
5293 static const char changepaste_help
[] =
5294 N_("Changes the no paste flag of objects.");
5296 /* %start-doc actions ChangePaste
5298 The "no paste flag" of a pad determines whether the solderpaste
5299 stencil will have an opening for the pad (no set) or if there wil be
5300 no solderpaste on the pad (set). This is used for things such as
5306 ActionChangePaste (int argc
, char **argv
, Coord x
, Coord y
)
5308 char *function
= ARG (0);
5311 switch (GetFunctionID (function
))
5313 case F_ToggleObject
:
5317 void *ptr1
, *ptr2
, *ptr3
;
5319 gui
->get_coords (_("Select an Object"), &x
, &y
);
5320 if ((type
= SearchScreen (x
, y
, PAD_TYPE
,
5321 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
5322 && ChangePaste ((PadType
*) ptr3
))
5323 IncrementUndoSerialNumber ();
5327 case F_SelectedPads
:
5329 if (ChangeSelectedPaste ())
5330 SetChangedFlag (true);
5337 /* --------------------------------------------------------------------------- */
5339 static const char select_syntax
[] =
5340 N_("Select(Object|ToggleObject)\n"
5341 "Select(All|Block|Connection)\n"
5342 "Select(ElementByName|ObjectByName|PadByName|PinByName)\n"
5343 "Select(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5344 "Select(TextByName|ViaByName|NetByName)\n"
5345 "Select(TextByName|ViaByName|NetByName, Name)\n"
5348 static const char select_help
[] = N_("Toggles or sets the selection.");
5350 /* %start-doc actions Select
5362 These all rely on having a regular expression parser built into
5363 @code{pcb}. If the name is not specified then the user is prompted
5364 for a pattern, and all objects that match the pattern and are of the
5365 type specified are selected.
5369 Selects the object under the cursor.
5372 Selects all objects in a rectangle indicated by the cursor.
5375 Selects all objects on the board.
5378 Selects all connections with the ``found'' flag set.
5381 Selects all connections with the ``connected'' flag set.
5384 Converts the selected objects to an element. This uses the highest
5385 numbered paste buffer.
5392 ActionSelect (int argc
, char **argv
, Coord x
, Coord y
)
5394 char *function
= ARG (0);
5397 switch (GetFunctionID (function
))
5399 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5401 /* select objects by their names */
5402 case F_ElementByName
:
5403 type
= ELEMENT_TYPE
;
5405 case F_ObjectByName
:
5426 char *pattern
= ARG (1);
5430 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5432 if (SelectObjectByName (type
, pattern
, true))
5433 SetChangedFlag (true);
5434 if (ARG (1) == NULL
)
5439 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5441 /* select a single object */
5442 case F_ToggleObject
:
5444 if (SelectObject ())
5445 SetChangedFlag (true);
5448 /* all objects in block */
5453 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5454 Crosshair
.AttachedBox
.Point2
.X
);
5455 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5456 Crosshair
.AttachedBox
.Point2
.Y
);
5457 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5458 Crosshair
.AttachedBox
.Point2
.X
);
5459 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5460 Crosshair
.AttachedBox
.Point2
.Y
);
5461 notify_crosshair_change (false);
5463 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5464 SelectBlock (&box
, true))
5466 SetChangedFlag (true);
5467 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5469 notify_crosshair_change (true);
5473 /* select all visible objects */
5478 box
.X1
= -MAX_COORD
;
5479 box
.Y1
= -MAX_COORD
;
5482 if (SelectBlock (&box
, true))
5483 SetChangedFlag (true);
5487 /* all logical connections */
5489 if (SelectByFlag (FOUNDFLAG
, true))
5492 IncrementUndoSerialNumber ();
5493 SetChangedFlag (true);
5497 /* all physical connections */
5499 if (SelectByFlag (CONNECTEDFLAG
, true))
5502 IncrementUndoSerialNumber ();
5503 SetChangedFlag (true);
5510 Note
.Buffer
= Settings
.BufferNumber
;
5511 SetBufferNumber (MAX_BUFFER
- 1);
5512 ClearBuffer (PASTEBUFFER
);
5513 gui
->get_coords (_("Select the Element's Mark Location"), &x
, &y
);
5514 x
= GridFit (x
, PCB
->Grid
, PCB
->GridOffsetX
);
5515 y
= GridFit (y
, PCB
->Grid
, PCB
->GridOffsetY
);
5516 AddSelectedToBuffer (PASTEBUFFER
, x
, y
, true);
5517 SaveUndoSerialNumber ();
5519 ConvertBufferToElement (PASTEBUFFER
);
5520 RestoreUndoSerialNumber ();
5521 CopyPastebufferToLayout (x
, y
);
5522 SetBufferNumber (Note
.Buffer
);
5534 /* FLAG(have_regex,FlagHaveRegex,0) */
5536 FlagHaveRegex (int parm
)
5538 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5545 /* --------------------------------------------------------------------------- */
5547 static const char unselect_syntax
[] =
5548 N_("Unselect(All|Block|Connection)\n"
5549 "Unselect(ElementByName|ObjectByName|PadByName|PinByName)\n"
5550 "Unselect(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5551 "Unselect(TextByName|ViaByName)\n"
5552 "Unselect(TextByName|ViaByName, Name)\n");
5554 static const char unselect_help
[] =
5555 N_("Unselects the object at the pointer location or the specified objects.");
5557 /* %start-doc actions Unselect
5562 Unselect all objects.
5565 Unselect all objects in a rectangle given by the cursor.
5568 Unselect all connections with the ``found'' flag set.
5577 These all rely on having a regular expression parser built into
5578 @code{pcb}. If the name is not specified then the user is prompted
5579 for a pattern, and all objects that match the pattern and are of the
5580 type specified are unselected.
5588 ActionUnselect (int argc
, char **argv
, Coord x
, Coord y
)
5590 char *function
= ARG (0);
5593 switch (GetFunctionID (function
))
5595 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5597 /* select objects by their names */
5598 case F_ElementByName
:
5599 type
= ELEMENT_TYPE
;
5601 case F_ObjectByName
:
5622 char *pattern
= ARG (1);
5626 gui
->prompt_for (_("Enter pattern:"), "")) != NULL
)
5628 if (SelectObjectByName (type
, pattern
, false))
5629 SetChangedFlag (true);
5630 if (ARG (1) == NULL
)
5635 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5637 /* all objects in block */
5642 box
.X1
= MIN (Crosshair
.AttachedBox
.Point1
.X
,
5643 Crosshair
.AttachedBox
.Point2
.X
);
5644 box
.Y1
= MIN (Crosshair
.AttachedBox
.Point1
.Y
,
5645 Crosshair
.AttachedBox
.Point2
.Y
);
5646 box
.X2
= MAX (Crosshair
.AttachedBox
.Point1
.X
,
5647 Crosshair
.AttachedBox
.Point2
.X
);
5648 box
.Y2
= MAX (Crosshair
.AttachedBox
.Point1
.Y
,
5649 Crosshair
.AttachedBox
.Point2
.Y
);
5650 notify_crosshair_change (false);
5652 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
&&
5653 SelectBlock (&box
, false))
5655 SetChangedFlag (true);
5656 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
5658 notify_crosshair_change (true);
5662 /* unselect all visible objects */
5667 box
.X1
= -MAX_COORD
;
5668 box
.Y1
= -MAX_COORD
;
5671 if (SelectBlock (&box
, false))
5672 SetChangedFlag (true);
5676 /* all logical connections */
5678 if (SelectByFlag (FOUNDFLAG
, false))
5681 IncrementUndoSerialNumber ();
5682 SetChangedFlag (true);
5686 /* all physical connections */
5688 if (SelectByFlag (CONNECTEDFLAG
, false))
5691 IncrementUndoSerialNumber ();
5692 SetChangedFlag (true);
5705 /* --------------------------------------------------------------------------- */
5707 static const char saveto_syntax
[] =
5708 N_("SaveTo(Layout|LayoutAs,filename)\n"
5709 "SaveTo(AllConnections|AllUnusedPins|ElementConnections,filename)\n"
5710 "SaveTo(PasteBuffer,filename)");
5712 static const char saveto_help
[] = N_("Saves data to a file.");
5714 /* %start-doc actions SaveTo
5719 Saves the current layout.
5722 Saves the current layout, and remembers the filename used.
5724 @item AllConnections
5725 Save all connections to a file.
5728 List all unused pins to a file.
5730 @item ElementConnections
5731 Save connections to the element at the cursor to a file.
5734 Save the content of the active Buffer to a file. This is the graphical way to create a footprint.
5741 ActionSaveTo (int argc
, char **argv
, Coord x
, Coord y
)
5748 if ( ! function
|| strcasecmp (function
, "Layout") == 0)
5750 if (SavePCB (PCB
->Filename
) == 0)
5751 SetChangedFlag (false);
5760 if (strcasecmp (function
, "LayoutAs") == 0)
5762 if (SavePCB (name
) == 0)
5764 SetChangedFlag (false);
5765 free (PCB
->Filename
);
5766 PCB
->Filename
= strdup (name
);
5767 if (gui
->notify_filename_changed
!= NULL
)
5768 gui
->notify_filename_changed ();
5773 if (strcasecmp (function
, "AllConnections") == 0)
5777 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5779 LookupConnectionsToAllElements (fp
);
5781 SetChangedFlag (true);
5786 if (strcasecmp (function
, "AllUnusedPins") == 0)
5790 if ((fp
= CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5792 LookupUnusedPins (fp
);
5794 SetChangedFlag (true);
5799 if (strcasecmp (function
, "ElementConnections") == 0)
5801 ElementType
*element
;
5806 if ((SearchScreen (Crosshair
.X
, Crosshair
.Y
, ELEMENT_TYPE
,
5807 &ptrtmp
, &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
5809 element
= (ElementType
*) ptrtmp
;
5811 CheckAndOpenFile (name
, true, false, &result
, NULL
)) != NULL
)
5813 LookupElementConnections (element
, fp
);
5815 SetChangedFlag (true);
5821 if (strcasecmp (function
, "PasteBuffer") == 0)
5823 return SaveBufferElements (name
);
5829 /* --------------------------------------------------------------------------- */
5831 static const char savesettings_syntax
[] =
5832 N_("SaveSettings()\n"
5833 "SaveSettings(local)");
5835 static const char savesettings_help
[] = N_("Saves settings.");
5837 /* %start-doc actions SaveSettings
5839 If you pass no arguments, the settings are stored in
5840 @code{$HOME/.pcb/settings}. If you pass the word @code{local} they're
5841 saved in @code{./pcb.settings}.
5846 ActionSaveSettings (int argc
, char **argv
, Coord x
, Coord y
)
5848 int locally
= argc
> 0 ? (strncasecmp (argv
[0], "local", 5) == 0) : 0;
5849 hid_save_settings (locally
);
5853 /* --------------------------------------------------------------------------- */
5855 static const char loadfrom_syntax
[] =
5856 N_("LoadFrom(Layout|LayoutToBuffer|ElementToBuffer|Netlist|Revert,filename)");
5858 static const char loadfrom_help
[] = N_("Load layout data from a file.");
5860 /* %start-doc actions LoadFrom
5862 This action assumes you know what the filename is. The various GUIs
5863 should have a similar @code{Load} action where the filename is
5864 optional, and will provide their own file selection mechanism to let
5865 you choose the file name.
5870 Loads an entire PCB layout, replacing the current one.
5872 @item LayoutToBuffer
5873 Loads an entire PCB layout to the paste buffer.
5875 @item ElementToBuffer
5876 Loads the given element file into the paste buffer. Element files
5877 contain only a single @code{Element} definition, such as the
5878 ``newlib'' library uses.
5881 Loads a new netlist, replacing any current netlist.
5884 Re-loads the current layout from its disk file, reverting any changes
5892 ActionLoadFrom (int argc
, char **argv
, Coord x
, Coord y
)
5903 if (strcasecmp (function
, "ElementToBuffer") == 0)
5905 notify_crosshair_change (false);
5906 if (LoadElementToBuffer (PASTEBUFFER
, name
, true))
5907 SetMode (PASTEBUFFER_MODE
);
5908 notify_crosshair_change (true);
5911 else if (strcasecmp (function
, "LayoutToBuffer") == 0)
5913 notify_crosshair_change (false);
5914 if (LoadLayoutToBuffer (PASTEBUFFER
, name
))
5915 SetMode (PASTEBUFFER_MODE
);
5916 notify_crosshair_change (true);
5919 else if (strcasecmp (function
, "Layout") == 0)
5921 if (!PCB
->Changed
||
5922 gui
->confirm_dialog (_("OK to override layout data?"), 0))
5926 else if (strcasecmp (function
, "Netlist") == 0)
5928 if (PCB
->Netlistname
)
5929 free (PCB
->Netlistname
);
5930 PCB
->Netlistname
= StripWhiteSpaceAndDup (name
);
5931 FreeLibraryMemory (&PCB
->NetlistLib
);
5932 ImportNetlist (PCB
->Netlistname
);
5935 else if (strcasecmp (function
, "Revert") == 0 && PCB
->Filename
5937 || gui
->confirm_dialog (_("OK to override changes?"), 0)))
5945 /* --------------------------------------------------------------------------- */
5947 static const char new_syntax
[] = N_("New([name])");
5949 static const char new_help
[] = N_("Starts a new layout.");
5951 /* %start-doc actions New
5953 If a name is not given, one is prompted for.
5958 ActionNew (int argc
, char **argv
, Coord x
, Coord y
)
5960 char *name
= ARG (0);
5962 if (!PCB
->Changed
|| gui
->confirm_dialog (_("OK to clear layout data?"), 0))
5965 name
= strdup (name
);
5967 name
= gui
->prompt_for (_("Enter the layout name:"), "");
5972 notify_crosshair_change (false);
5973 /* do emergency saving
5974 * clear the old struct and allocate memory for the new one
5976 if (PCB
->Changed
&& Settings
.SaveInTMP
)
5980 PCB
= CreateNewPCB ();
5981 CreateNewPCBPost (PCB
, 1);
5983 /* setup the new name and reset some values to default */
5987 ResetStackAndVisibility ();
5988 SetCrosshairRange (0, 0, PCB
->MaxWidth
, PCB
->MaxHeight
);
5989 CenterDisplay (PCB
->MaxWidth
/ 2, PCB
->MaxHeight
/ 2);
5992 hid_action ("PCBChanged");
5993 notify_crosshair_change (true);
6000 * \brief No operation, just for testing purposes.
6001 * syntax: Bell(volume)
6004 ActionBell (char *volume
)
6009 /* --------------------------------------------------------------------------- */
6011 static const char pastebuffer_syntax
[] =
6012 N_("PasteBuffer(AddSelected|Clear|1..MAX_BUFFER)\n"
6013 "PasteBuffer(Rotate, 1..3)\n"
6014 "PasteBuffer(Convert|Save|Restore|Mirror)\n"
6015 "PasteBuffer(ToLayout, X, Y, units)");
6017 static const char pastebuffer_help
[] =
6018 N_("Various operations on the paste buffer.");
6020 /* %start-doc actions PasteBuffer
6022 There are a number of paste buffers; the actual limit is a
6023 compile-time constant @code{MAX_BUFFER} in @file{globalconst.h}. It
6024 is currently @code{5}. One of these is the ``current'' paste buffer,
6025 often referred to as ``the'' paste buffer.
6030 Copies the selected objects to the current paste buffer.
6033 Remove all objects from the current paste buffer.
6036 Convert the current paste buffer to an element. Vias are converted to
6037 pins, lines are converted to pads.
6040 Convert any elements in the paste buffer back to vias and lines.
6043 Flip all objects in the paste buffer vertically (up/down flip). To mirror
6044 horizontally, combine this with rotations.
6047 Rotates the current buffer. The number to pass is 1..3, where 1 means
6048 90 degrees counter clockwise, 2 means 180 degrees, and 3 means 90
6049 degrees clockwise (270 CCW).
6052 Saves any elements in the current buffer to the indicated file.
6055 Pastes any elements in the current buffer to the indicated X, Y
6056 coordinates in the layout. The @code{X} and @code{Y} are treated like
6057 @code{delta} is for many other objects. For each, if it's prefixed by
6058 @code{+} or @code{-}, then that amount is relative to the last
6059 location. Otherwise, it's absolute. Units can be
6060 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
6061 units, currently 1/100 mil.
6065 Selects the given buffer to be the current paste buffer.
6072 ActionPasteBuffer (int argc
, char **argv
, Coord x
, Coord y
)
6074 char *function
= argc
? argv
[0] : (char *)"";
6075 char *sbufnum
= argc
> 1 ? argv
[1] : (char *)"";
6077 static char *default_file
= NULL
;
6080 notify_crosshair_change (false);
6083 switch (GetFunctionID (function
))
6085 /* clear contents of paste buffer */
6087 ClearBuffer (PASTEBUFFER
);
6090 /* copies objects to paste buffer */
6092 AddSelectedToBuffer (PASTEBUFFER
, 0, 0, false);
6095 /* converts buffer contents into an element */
6097 ConvertBufferToElement (PASTEBUFFER
);
6100 /* break up element for editing */
6102 SmashBufferElement (PASTEBUFFER
);
6107 MirrorBuffer (PASTEBUFFER
);
6113 RotateBuffer (PASTEBUFFER
, (BYTE
) atoi (sbufnum
));
6114 SetCrosshairRangeToBuffer ();
6119 if (PASTEBUFFER
->Data
->ElementN
== 0)
6121 Message (_("Buffer has no elements!\n"));
6127 name
= gui
->fileselect (_("Save Paste Buffer As ..."),
6128 _("Choose a file to save the contents of the\n"
6129 "paste buffer to.\n"),
6130 default_file
, ".fp", "footprint",
6135 free (default_file
);
6136 default_file
= NULL
;
6140 default_file
= strdup (name
);
6151 if ((exist
= fopen (name
, "r")))
6155 confirm_dialog (_("File exists! Ok to overwrite?"), 0))
6156 SaveBufferElements (name
);
6159 SaveBufferElements (name
);
6161 if (free_name
&& name
)
6168 static Coord oldx
= 0, oldy
= 0;
6176 else if (argc
== 3 || argc
== 4)
6178 x
= GetValue (ARG (1), ARG (3), &absolute
);
6181 y
= GetValue (ARG (2), ARG (3), &absolute
);
6187 notify_crosshair_change (true);
6188 AFAIL (pastebuffer
);
6193 if (CopyPastebufferToLayout (x
, y
))
6194 SetChangedFlag (true);
6201 int number
= atoi (function
);
6203 /* correct number */
6205 SetBufferNumber (number
- 1);
6210 notify_crosshair_change (true);
6214 /* --------------------------------------------------------------------------- */
6216 static const char undo_syntax
[] = N_("Undo()\n"
6219 static const char undo_help
[] = N_("Undo recent changes.");
6221 /* %start-doc actions Undo
6223 The unlimited undo feature of @code{Pcb} allows you to recover from
6224 most operations that materially affect you work. Calling
6225 @code{Undo()} without any parameter recovers from the last (non-undo)
6226 operation. @code{ClearList} is used to release the allocated
6227 memory. @code{ClearList} is called whenever a new layout is started or
6228 loaded. See also @code{Redo} and @code{Atomic}.
6230 Note that undo groups operations by serial number; changes with the
6231 same serial number will be undone (or redone) as a group. See
6237 ActionUndo (int argc
, char **argv
, Coord x
, Coord y
)
6239 char *function
= ARG (0);
6240 if (!function
|| !*function
)
6242 /* don't allow undo in the middle of an operation */
6243 if (Settings
.Mode
!= POLYGONHOLE_MODE
&&
6244 Crosshair
.AttachedObject
.State
!= STATE_FIRST
)
6246 if (Crosshair
.AttachedBox
.State
!= STATE_FIRST
6247 && Settings
.Mode
!= ARC_MODE
)
6249 /* undo the last operation */
6251 notify_crosshair_change (false);
6252 if ((Settings
.Mode
== POLYGON_MODE
||
6253 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6254 Crosshair
.AttachedPolygon
.PointN
)
6256 GoToPreviousPoint ();
6257 notify_crosshair_change (true);
6260 /* move anchor point if undoing during line creation */
6261 if (Settings
.Mode
== LINE_MODE
)
6263 if (Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6265 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6266 Undo (true); /* undo the connection find */
6267 Crosshair
.AttachedLine
.State
= STATE_FIRST
;
6268 SetLocalRef (0, 0, false);
6269 notify_crosshair_change (true);
6272 if (Crosshair
.AttachedLine
.State
== STATE_THIRD
)
6275 void *ptr1
, *ptr3
, *ptrtmp
;
6277 /* this search is guaranteed to succeed */
6278 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6280 Crosshair
.AttachedLine
.Point1
.X
,
6281 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6282 ptr2
= (LineType
*) ptrtmp
;
6284 /* save both ends of line */
6285 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point1
.X
;
6286 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point1
.Y
;
6287 if ((type
= Undo (true)))
6288 SetChangedFlag (true);
6289 /* check that the undo was of the right type */
6290 if ((type
& UNDO_CREATE
) == 0)
6292 /* wrong undo type, restore anchor points */
6293 Crosshair
.AttachedLine
.Point2
.X
=
6294 Crosshair
.AttachedLine
.Point1
.X
;
6295 Crosshair
.AttachedLine
.Point2
.Y
=
6296 Crosshair
.AttachedLine
.Point1
.Y
;
6297 notify_crosshair_change (true);
6300 /* move to new anchor */
6301 Crosshair
.AttachedLine
.Point1
.X
=
6302 Crosshair
.AttachedLine
.Point2
.X
;
6303 Crosshair
.AttachedLine
.Point1
.Y
=
6304 Crosshair
.AttachedLine
.Point2
.Y
;
6305 /* check if an intermediate point was removed */
6306 if (type
& UNDO_REMOVE
)
6308 /* this search should find the restored line */
6309 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6312 Crosshair
.AttachedLine
.Point2
.X
,
6313 Crosshair
.AttachedLine
.Point2
.Y
, 0);
6314 ptr2
= (LineType
*) ptrtmp
;
6315 if (TEST_FLAG (AUTODRCFLAG
, PCB
))
6317 /* undo loses CONNECTEDFLAG and FOUNDFLAG */
6318 SET_FLAG(CONNECTEDFLAG
, ptr2
);
6319 SET_FLAG(FOUNDFLAG
, ptr2
);
6320 DrawLine (CURRENT
, ptr2
);
6322 Crosshair
.AttachedLine
.Point1
.X
=
6323 Crosshair
.AttachedLine
.Point2
.X
= ptr2
->Point2
.X
;
6324 Crosshair
.AttachedLine
.Point1
.Y
=
6325 Crosshair
.AttachedLine
.Point2
.Y
= ptr2
->Point2
.Y
;
6327 FitCrosshairIntoGrid (Crosshair
.X
, Crosshair
.Y
);
6328 AdjustAttachedObjects ();
6329 if (--addedLines
== 0)
6331 Crosshair
.AttachedLine
.State
= STATE_SECOND
;
6332 lastLayer
= CURRENT
;
6336 /* this search is guaranteed to succeed too */
6337 SearchObjectByLocation (LINE_TYPE
| RATLINE_TYPE
, &ptr1
,
6340 Crosshair
.AttachedLine
.Point1
.X
,
6341 Crosshair
.AttachedLine
.Point1
.Y
, 0);
6342 ptr2
= (LineType
*) ptrtmp
;
6343 lastLayer
= (LayerType
*) ptr1
;
6345 notify_crosshair_change (true);
6349 if (Settings
.Mode
== ARC_MODE
)
6351 if (Crosshair
.AttachedBox
.State
== STATE_SECOND
)
6353 Crosshair
.AttachedBox
.State
= STATE_FIRST
;
6354 notify_crosshair_change (true);
6357 if (Crosshair
.AttachedBox
.State
== STATE_THIRD
)
6359 void *ptr1
, *ptr2
, *ptr3
;
6361 /* guaranteed to succeed */
6362 SearchObjectByLocation (ARC_TYPE
, &ptr1
, &ptr2
, &ptr3
,
6363 Crosshair
.AttachedBox
.Point1
.X
,
6364 Crosshair
.AttachedBox
.Point1
.Y
, 0);
6365 bx
= GetArcEnds ((ArcType
*) ptr2
);
6366 Crosshair
.AttachedBox
.Point1
.X
=
6367 Crosshair
.AttachedBox
.Point2
.X
= bx
->X1
;
6368 Crosshair
.AttachedBox
.Point1
.Y
=
6369 Crosshair
.AttachedBox
.Point2
.Y
= bx
->Y1
;
6370 AdjustAttachedObjects ();
6371 if (--addedLines
== 0)
6372 Crosshair
.AttachedBox
.State
= STATE_SECOND
;
6375 /* undo the last destructive operation */
6377 SetChangedFlag (true);
6381 switch (GetFunctionID (function
))
6383 /* clear 'undo objects' list */
6385 ClearUndoList (false);
6389 notify_crosshair_change (true);
6393 /* --------------------------------------------------------------------------- */
6395 static const char redo_syntax
[] = N_("Redo()");
6397 static const char redo_help
[] = N_("Redo recent \"undo\" operations.");
6399 /* %start-doc actions Redo
6401 This routine allows you to recover from the last undo command. You
6402 might want to do this if you thought that undo was going to revert
6403 something other than what it actually did (in case you are confused
6404 about which operations are un-doable), or if you have been backing up
6405 through a long undo list and over-shoot your stopping point. Any
6406 change that is made since the undo in question will trim the redo
6407 list. For example if you add ten lines, then undo three of them you
6408 could use redo to put them back, but if you move a line on the board
6409 before performing the redo, you will lose the ability to "redo" the
6410 three "undone" lines.
6415 ActionRedo (int argc
, char **argv
, Coord x
, Coord y
)
6417 if (((Settings
.Mode
== POLYGON_MODE
||
6418 Settings
.Mode
== POLYGONHOLE_MODE
) &&
6419 Crosshair
.AttachedPolygon
.PointN
) ||
6420 Crosshair
.AttachedLine
.State
== STATE_SECOND
)
6422 notify_crosshair_change (false);
6425 SetChangedFlag (true);
6426 if (Settings
.Mode
== LINE_MODE
&&
6427 Crosshair
.AttachedLine
.State
!= STATE_FIRST
)
6429 LineType
*line
= g_list_last (CURRENT
->Line
)->data
;
6430 Crosshair
.AttachedLine
.Point1
.X
=
6431 Crosshair
.AttachedLine
.Point2
.X
= line
->Point2
.X
;
6432 Crosshair
.AttachedLine
.Point1
.Y
=
6433 Crosshair
.AttachedLine
.Point2
.Y
= line
->Point2
.Y
;
6437 notify_crosshair_change (true);
6441 /* --------------------------------------------------------------------------- */
6443 static const char polygon_syntax
[] = N_("Polygon(Close|PreviousPoint)");
6445 static const char polygon_help
[] = N_("Some polygon related stuff.");
6447 /* %start-doc actions Polygon
6449 Polygons need a special action routine to make life easier.
6454 Creates the final segment of the polygon. This may fail if clipping
6455 to 45 degree lines is switched on, in which case a warning is issued.
6458 Resets the newly entered corner to the previous one. The Undo action
6459 will call Polygon(PreviousPoint) when appropriate to do so.
6466 ActionPolygon (int argc
, char **argv
, Coord x
, Coord y
)
6468 char *function
= ARG (0);
6469 if (function
&& Settings
.Mode
== POLYGON_MODE
)
6471 notify_crosshair_change (false);
6472 switch (GetFunctionID (function
))
6474 /* close open polygon if possible */
6479 /* go back to the previous point */
6480 case F_PreviousPoint
:
6481 GoToPreviousPoint ();
6484 notify_crosshair_change (true);
6489 /* --------------------------------------------------------------------------- */
6491 static const char routestyle_syntax
[] = N_("RouteStyle(1|2|3|4)");
6493 static const char routestyle_help
[] =
6494 N_("Copies the indicated routing style into the current sizes.");
6496 /* %start-doc actions RouteStyle
6501 ActionRouteStyle (int argc
, char **argv
, Coord x
, Coord y
)
6503 char *str
= ARG (0);
6504 RouteStyleType
*rts
;
6509 number
= atoi (str
);
6510 if (number
> 0 && number
<= NUM_STYLES
)
6512 rts
= &PCB
->RouteStyle
[number
- 1];
6513 SetLineSize (rts
->Thick
);
6514 SetViaSize (rts
->Diameter
, true);
6515 SetViaDrillingHole (rts
->Hole
, true);
6516 SetKeepawayWidth (rts
->Keepaway
);
6517 hid_action("RouteStylesChanged");
6524 /* --------------------------------------------------------------------------- */
6526 static const char moveobject_syntax
[] = N_("MoveObject(X,Y,dim)");
6528 static const char moveobject_help
[] =
6529 N_("Moves the object under the crosshair.");
6531 /* %start-doc actions MoveObject
6533 The @code{X} and @code{Y} are treated like @code{delta} is for many
6534 other objects. For each, if it's prefixed by @code{+} or @code{-},
6535 then that amount is relative. Otherwise, it's absolute. Units can be
6536 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
6537 units, currently 1/100 mil.
6542 ActionMoveObject (int argc
, char **argv
, Coord x
, Coord y
)
6544 char *x_str
= ARG (0);
6545 char *y_str
= ARG (1);
6546 char *units
= ARG (2);
6548 bool absolute1
, absolute2
;
6549 void *ptr1
, *ptr2
, *ptr3
;
6552 ny
= GetValue (y_str
, units
, &absolute1
);
6553 nx
= GetValue (x_str
, units
, &absolute2
);
6555 type
= SearchScreen (x
, y
, MOVE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6556 if (type
== NO_TYPE
)
6558 Message (_("Nothing found under crosshair\n"));
6565 Crosshair
.AttachedObject
.RubberbandN
= 0;
6566 if (TEST_FLAG (RUBBERBANDFLAG
, PCB
))
6567 LookupRubberbandLines (type
, ptr1
, ptr2
, ptr3
);
6568 if (type
== ELEMENT_TYPE
)
6569 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
6570 MoveObjectAndRubberband (type
, ptr1
, ptr2
, ptr3
, nx
, ny
);
6571 SetChangedFlag (true);
6575 /* --------------------------------------------------------------------------- */
6577 static const char movetocurrentlayer_syntax
[] =
6578 N_("MoveToCurrentLayer(Object|SelectedObjects)");
6580 static const char movetocurrentlayer_help
[] =
6581 N_("Moves objects to the current layer.");
6583 /* %start-doc actions MoveToCurrentLayer
6585 Note that moving an element from a component layer to a solder layer,
6586 or from solder to component, won't automatically flip it. Use the
6587 @code{Flip()} action to do that.
6592 ActionMoveToCurrentLayer (int argc
, char **argv
, Coord x
, Coord y
)
6594 char *function
= ARG (0);
6597 switch (GetFunctionID (function
))
6602 void *ptr1
, *ptr2
, *ptr3
;
6604 gui
->get_coords (_("Select an Object"), &x
, &y
);
6606 SearchScreen (x
, y
, MOVETOLAYER_TYPES
,
6607 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6608 if (MoveObjectToLayer (type
, ptr1
, ptr2
, ptr3
, CURRENT
, false))
6609 SetChangedFlag (true);
6613 case F_SelectedObjects
:
6615 if (MoveSelectedObjectsToLayer (CURRENT
))
6616 SetChangedFlag (true);
6624 static const char setsame_syntax
[] = N_("SetSame()");
6626 static const char setsame_help
[] =
6627 N_("Sets current layer and sizes to match indicated item.");
6629 /* %start-doc actions SetSame
6631 When invoked over any line, arc, polygon, or via, this changes the
6632 current layer to be the layer that item is on, and changes the current
6633 sizes (thickness, keepaway, drill, etc) according to that item.
6638 ActionSetSame (int argc
, char **argv
, Coord x
, Coord y
)
6640 void *ptr1
, *ptr2
, *ptr3
;
6642 LayerType
*layer
= CURRENT
;
6644 type
= SearchScreen (x
, y
, CLONE_TYPES
, &ptr1
, &ptr2
, &ptr3
);
6645 /* set layer current and size from line or arc */
6649 notify_crosshair_change (false);
6650 Settings
.LineThickness
= ((LineType
*) ptr2
)->Thickness
;
6651 Settings
.Keepaway
= ((LineType
*) ptr2
)->Clearance
/ 2;
6652 layer
= (LayerType
*) ptr1
;
6653 if (Settings
.Mode
!= LINE_MODE
)
6654 SetMode (LINE_MODE
);
6655 notify_crosshair_change (true);
6656 hid_action ("RouteStylesChanged");
6660 notify_crosshair_change (false);
6661 Settings
.LineThickness
= ((ArcType
*) ptr2
)->Thickness
;
6662 Settings
.Keepaway
= ((ArcType
*) ptr2
)->Clearance
/ 2;
6663 layer
= (LayerType
*) ptr1
;
6664 if (Settings
.Mode
!= ARC_MODE
)
6666 notify_crosshair_change (true);
6667 hid_action ("RouteStylesChanged");
6671 layer
= (LayerType
*) ptr1
;
6675 notify_crosshair_change (false);
6676 Settings
.ViaThickness
= ((PinType
*) ptr2
)->Thickness
;
6677 Settings
.ViaDrillingHole
= ((PinType
*) ptr2
)->DrillingHole
;
6678 Settings
.Keepaway
= ((PinType
*) ptr2
)->Clearance
/ 2;
6679 if (Settings
.Mode
!= VIA_MODE
)
6681 notify_crosshair_change (true);
6682 hid_action ("RouteStylesChanged");
6688 if (layer
!= CURRENT
)
6690 ChangeGroupVisibility (GetLayerNumber (PCB
->Data
, layer
), true, true);
6697 /* --------------------------------------------------------------------------- */
6699 static const char setflag_syntax
[] =
6700 N_("SetFlag(Object|Selected|SelectedObjects, flag)\n"
6701 "SetFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6702 "SetFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6703 "SetFlag(SelectedElements, flag)\n"
6704 "flag = square | octagon | thermal | join");
6706 static const char setflag_help
[] = N_("Sets flags on objects.");
6708 /* %start-doc actions SetFlag
6710 Turns the given flag on, regardless of its previous setting. See
6714 SetFlag(SelectedPins,thermal)
6720 ActionSetFlag (int argc
, char **argv
, Coord x
, Coord y
)
6722 char *function
= ARG (0);
6723 char *flag
= ARG (1);
6724 ChangeFlag (function
, flag
, 1, "SetFlag");
6728 /* --------------------------------------------------------------------------- */
6730 static const char clrflag_syntax
[] =
6731 N_("ClrFlag(Object|Selected|SelectedObjects, flag)\n"
6732 "ClrFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6733 "ClrFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6734 "ClrFlag(SelectedElements, flag)\n"
6735 "flag = square | octagon | thermal | join");
6737 static const char clrflag_help
[] = N_("Clears flags on objects.");
6739 /* %start-doc actions ClrFlag
6741 Turns the given flag off, regardless of its previous setting. See
6745 ClrFlag(SelectedLines,join)
6751 ActionClrFlag (int argc
, char **argv
, Coord x
, Coord y
)
6753 char *function
= ARG (0);
6754 char *flag
= ARG (1);
6755 ChangeFlag (function
, flag
, 0, "ClrFlag");
6759 /* --------------------------------------------------------------------------- */
6761 static const char changeflag_syntax
[] =
6762 N_("ChangeFlag(Object|Selected|SelectedObjects, flag, value)\n"
6763 "ChangeFlag(SelectedLines|SelectedPins|SelectedVias, flag, value)\n"
6764 "ChangeFlag(SelectedPads|SelectedTexts|SelectedNames, flag, value)\n"
6765 "ChangeFlag(SelectedElements, flag, value)\n"
6766 "flag = square | octagon | thermal | join\n"
6769 static const char changeflag_help
[] = N_("Sets or clears flags on objects.");
6771 /* %start-doc actions ChangeFlag
6773 Toggles the given flag on the indicated object(s). The flag may be
6774 one of the flags listed above (square, octagon, thermal, join). The
6775 value may be the number 0 or 1. If the value is 0, the flag is
6776 cleared. If the value is 1, the flag is set.
6781 ActionChangeFlag (int argc
, char **argv
, Coord x
, Coord y
)
6783 char *function
= ARG (0);
6784 char *flag
= ARG (1);
6785 int value
= argc
> 2 ? atoi (argv
[2]) : -1;
6786 if (value
!= 0 && value
!= 1)
6789 ChangeFlag (function
, flag
, value
, "ChangeFlag");
6795 ChangeFlag (char *what
, char *flag_name
, int value
, char *cmd_name
)
6797 bool (*set_object
) (int, void *, void *, void *);
6798 bool (*set_selected
) (int);
6800 if (NSTRCMP (flag_name
, "square") == 0)
6802 set_object
= value
? SetObjectSquare
: ClrObjectSquare
;
6803 set_selected
= value
? SetSelectedSquare
: ClrSelectedSquare
;
6805 else if (NSTRCMP (flag_name
, "octagon") == 0)
6807 set_object
= value
? SetObjectOctagon
: ClrObjectOctagon
;
6808 set_selected
= value
? SetSelectedOctagon
: ClrSelectedOctagon
;
6810 else if (NSTRCMP (flag_name
, "join") == 0)
6812 /* Note: these are backwards, because the flag is "clear" but
6813 the command is "join". */
6814 set_object
= value
? ClrObjectJoin
: SetObjectJoin
;
6815 set_selected
= value
? ClrSelectedJoin
: SetSelectedJoin
;
6819 Message (_("%s(): Flag \"%s\" is not valid\n"), cmd_name
, flag_name
);
6823 switch (GetFunctionID (what
))
6828 void *ptr1
, *ptr2
, *ptr3
;
6831 SearchScreen (Crosshair
.X
, Crosshair
.Y
, CHANGESIZE_TYPES
,
6832 &ptr1
, &ptr2
, &ptr3
)) != NO_TYPE
)
6833 if (TEST_FLAG (LOCKFLAG
, (PinType
*) ptr2
))
6834 Message (_("Sorry, the object is locked\n"));
6835 if (set_object (type
, ptr1
, ptr2
, ptr3
))
6836 SetChangedFlag (true);
6840 case F_SelectedVias
:
6841 if (set_selected (VIA_TYPE
))
6842 SetChangedFlag (true);
6845 case F_SelectedPins
:
6846 if (set_selected (PIN_TYPE
))
6847 SetChangedFlag (true);
6850 case F_SelectedPads
:
6851 if (set_selected (PAD_TYPE
))
6852 SetChangedFlag (true);
6855 case F_SelectedLines
:
6856 if (set_selected (LINE_TYPE
))
6857 SetChangedFlag (true);
6860 case F_SelectedTexts
:
6861 if (set_selected (TEXT_TYPE
))
6862 SetChangedFlag (true);
6865 case F_SelectedNames
:
6866 if (set_selected (ELEMENTNAME_TYPE
))
6867 SetChangedFlag (true);
6870 case F_SelectedElements
:
6871 if (set_selected (ELEMENT_TYPE
))
6872 SetChangedFlag (true);
6876 case F_SelectedObjects
:
6877 if (set_selected (CHANGESIZE_TYPES
))
6878 SetChangedFlag (true);
6883 /* --------------------------------------------------------------------------- */
6885 static const char executefile_syntax
[] = N_("ExecuteFile(filename)");
6887 static const char executefile_help
[] = N_("Run actions from the given file.");
6889 /* %start-doc actions ExecuteFile
6891 Lines starting with @code{#} are ignored.
6896 ActionExecuteFile (int argc
, char **argv
, Coord x
, Coord y
)
6905 AFAIL (executefile
);
6909 if ((fp
= fopen (fname
, "r")) == NULL
)
6911 fprintf (stderr
, _("Could not open actions file \"%s\".\n"), fname
);
6916 defer_needs_update
= 0;
6917 while (fgets (line
, sizeof (line
), fp
) != NULL
)
6922 /* eat the trailing newline */
6923 while (*sp
&& *sp
!= '\r' && *sp
!= '\n')
6927 /* eat leading spaces and tabs */
6929 while (*sp
&& (*sp
== ' ' || *sp
== '\t'))
6933 * if we have anything left and its not a comment line
6937 if (*sp
&& *sp
!= '#')
6939 /*Message ("%s : line %-3d : \"%s\"\n", fname, n, sp);*/
6940 hid_parse_actions (sp
);
6945 if (defer_needs_update
)
6947 IncrementUndoSerialNumber ();
6948 gui
->invalidate_all ();
6954 /* --------------------------------------------------------------------------- */
6957 ActionPSCalib (int argc
, char **argv
, Coord x
, Coord y
)
6959 HID
*ps
= hid_find_exporter ("ps");
6960 ps
->calibrate (0.0,0.0);
6964 /* --------------------------------------------------------------------------- */
6966 static ElementType
*element_cache
= NULL
;
6968 static ElementType
*
6969 find_element_by_refdes (char *refdes
)
6972 && NAMEONPCB_NAME(element_cache
)
6973 && strcmp (NAMEONPCB_NAME(element_cache
), refdes
) == 0)
6974 return element_cache
;
6976 ELEMENT_LOOP (PCB
->Data
);
6978 if (NAMEONPCB_NAME(element
)
6979 && strcmp (NAMEONPCB_NAME(element
), refdes
) == 0)
6981 element_cache
= element
;
6982 return element_cache
;
6989 static AttributeType
*
6990 lookup_attr (AttributeListType
*list
, const char *name
)
6993 for (i
=0; i
<list
->Number
; i
++)
6994 if (strcmp (list
->List
[i
].name
, name
) == 0)
6995 return & list
->List
[i
];
7000 delete_attr (AttributeListType
*list
, AttributeType
*attr
)
7002 int idx
= attr
- list
->List
;
7003 if (idx
< 0 || idx
>= list
->Number
)
7005 if (list
->Number
- idx
> 1)
7006 memmove (attr
, attr
+1, (list
->Number
- idx
- 1) * sizeof(AttributeType
));
7010 /* ---------------------------------------------------------------- */
7011 static const char elementlist_syntax
[] =
7012 N_("ElementList(Start|Done|Need,<refdes>,<footprint>,<value>)");
7014 static const char elementlist_help
[] =
7015 N_("Adds the given element if it doesn't already exist.");
7017 /* %start-doc actions elementlist
7022 Indicates the start of an element list; call this before any Need
7026 Searches the board for an element with a matching refdes.
7028 If found, the value and footprint are updated.
7030 If not found, a new element is created with the given footprint and value.
7033 Compares the list of elements needed since the most recent
7034 @code{start} with the list of elements actually on the board. Any
7035 elements that weren't listed are selected, so that the user may delete
7042 static int number_of_footprints_not_found
;
7045 parse_layout_attribute_units (char *name
, int def
)
7047 const char *as
= AttributeGet (PCB
, name
);
7050 return GetValue (as
, NULL
, NULL
);
7054 ActionElementList (int argc
, char **argv
, Coord x
, Coord y
)
7056 ElementType
*e
= NULL
;
7057 char *refdes
, *value
, *footprint
, *old
;
7062 AFAIL (elementlist
);
7067 printf("Entered ActionElementList, executing function %s\n", function
);
7070 if (strcasecmp (function
, "start") == 0)
7072 ELEMENT_LOOP (PCB
->Data
);
7074 CLEAR_FLAG (FOUNDFLAG
, element
);
7077 element_cache
= NULL
;
7078 number_of_footprints_not_found
= 0;
7082 if (strcasecmp (function
, "done") == 0)
7084 ELEMENT_LOOP (PCB
->Data
);
7086 if (TEST_FLAG (FOUNDFLAG
, element
))
7088 CLEAR_FLAG (FOUNDFLAG
, element
);
7090 else if (! EMPTY_STRING_P (NAMEONPCB_NAME (element
)))
7092 /* Unnamed elements should remain untouched */
7093 SET_FLAG (SELECTEDFLAG
, element
);
7097 if (number_of_footprints_not_found
> 0)
7098 gui
->confirm_dialog (_("Not all requested footprints were found.\n"
7099 "See the message log for details"),
7104 if (strcasecmp (function
, "need") != 0)
7105 AFAIL (elementlist
);
7108 AFAIL (elementlist
);
7117 args
[0] = footprint
;
7122 printf(" ... footprint = %s\n", footprint
);
7123 printf(" ... refdes = %s\n", refdes
);
7124 printf(" ... value = %s\n", value
);
7127 e
= find_element_by_refdes (refdes
);
7134 printf(" ... Footprint not on board, need to add it.\n");
7136 /* Not on board, need to add it. */
7137 if (LoadFootprint(argc
, args
, x
, y
))
7139 number_of_footprints_not_found
++;
7143 nx
= PCB
->MaxWidth
/ 2;
7144 ny
= PCB
->MaxHeight
/ 2;
7145 d
= MIN (PCB
->MaxWidth
, PCB
->MaxHeight
) / 10;
7147 nx
= parse_layout_attribute_units ("import::newX", nx
);
7148 ny
= parse_layout_attribute_units ("import::newY", ny
);
7149 d
= parse_layout_attribute_units ("import::disperse", d
);
7153 nx
+= rand () % (d
*2) - d
;
7154 ny
+= rand () % (d
*2) - d
;
7159 if (nx
>= PCB
->MaxWidth
)
7160 nx
= PCB
->MaxWidth
- 1;
7163 if (ny
>= PCB
->MaxHeight
)
7164 ny
= PCB
->MaxHeight
- 1;
7166 /* Place components onto center of board. */
7167 if (CopyPastebufferToLayout (nx
, ny
))
7168 SetChangedFlag (true);
7171 else if (e
&& DESCRIPTION_NAME(e
) && strcmp (DESCRIPTION_NAME(e
), footprint
) != 0)
7174 printf(" ... Footprint on board, but different from footprint loaded.\n");
7180 /* Different footprint, we need to swap them out. */
7181 if (LoadFootprint(argc
, args
, x
, y
))
7183 number_of_footprints_not_found
++;
7187 er
= ElementOrientation (e
);
7188 pe
= PASTEBUFFER
->Data
->Element
->data
;
7190 MirrorElementCoordinates (PASTEBUFFER
->Data
, pe
, pe
->MarkY
*2 - PCB
->MaxHeight
);
7191 pr
= ElementOrientation (pe
);
7197 RotateElementLowLevel (PASTEBUFFER
->Data
, pe
, pe
->MarkX
, pe
->MarkY
, (er
-pr
+4)%4);
7199 for (i
=0; i
<MAX_ELEMENTNAMES
; i
++)
7201 pe
->Name
[i
].X
= e
->Name
[i
].X
- mx
+ pe
->MarkX
;
7202 pe
->Name
[i
].Y
= e
->Name
[i
].Y
- my
+ pe
->MarkY
;
7203 pe
->Name
[i
].Direction
= e
->Name
[i
].Direction
;
7204 pe
->Name
[i
].Scale
= e
->Name
[i
].Scale
;
7209 if (CopyPastebufferToLayout (mx
, my
))
7210 SetChangedFlag (true);
7213 /* Now reload footprint */
7214 element_cache
= NULL
;
7215 e
= find_element_by_refdes (refdes
);
7217 old
= ChangeElementText (PCB
, PCB
->Data
, e
, NAMEONPCB_INDEX
, strdup (refdes
));
7220 old
= ChangeElementText (PCB
, PCB
->Data
, e
, VALUE_INDEX
, strdup (value
));
7224 SET_FLAG (FOUNDFLAG
, e
);
7227 printf(" ... Leaving ActionElementList.\n");
7233 /* ---------------------------------------------------------------- */
7234 static const char elementsetattr_syntax
[] =
7235 N_("ElementSetAttr(refdes,name[,value])");
7237 static const char elementsetattr_help
[] =
7238 N_("Sets or clears an element-specific attribute.");
7240 /* %start-doc actions elementsetattr
7242 If a value is specified, the named attribute is added (if not already
7243 present) or changed (if it is) to the given value. If the value is
7244 not specified, the given attribute is removed if present.
7249 ActionElementSetAttr (int argc
, char **argv
, Coord x
, Coord y
)
7251 ElementType
*e
= NULL
;
7252 char *refdes
, *name
, *value
;
7253 AttributeType
*attr
;
7257 AFAIL (changepinname
);
7264 ELEMENT_LOOP (PCB
->Data
);
7266 if (NSTRCMP (refdes
, NAMEONPCB_NAME (element
)) == 0)
7276 Message(_("Cannot change attribute of %s - element not found\n"), refdes
);
7280 attr
= lookup_attr (&e
->Attributes
, name
);
7285 attr
->value
= strdup (value
);
7287 if (attr
&& ! value
)
7289 delete_attr (& e
->Attributes
, attr
);
7293 CreateNewAttribute (& e
->Attributes
, name
, value
);
7299 /* ---------------------------------------------------------------- */
7300 static const char execcommand_syntax
[] = N_("ExecCommand(command)");
7302 static const char execcommand_help
[] = N_("Runs a command.");
7304 /* %start-doc actions execcommand
7306 Runs the given command, which is a system executable.
7311 ActionExecCommand (int argc
, char **argv
, Coord x
, Coord y
)
7317 AFAIL (execcommand
);
7322 if (system (command
))
7327 /* ---------------------------------------------------------------- */
7330 pcb_spawnvp (char **argv
)
7332 #ifdef HAVE__SPAWNVP
7333 int result
= _spawnvp (_P_WAIT
, argv
[0], (const char * const *) argv
);
7344 Message(_("Cannot fork!"));
7350 execvp (argv
[0], argv
);
7363 /* ---------------------------------------------------------------- */
7366 * \brief Creates a new temporary file name.
7368 * Hopefully the operating system provides a mkdtemp() function to
7369 * securily create a temporary directory with mode 0700.\n
7370 * If so then that directory is created and the returned string is made
7371 * up of the directory plus the name variable.\n
7374 * tempfile_name_new ("myfile") might return
7375 * "/var/tmp/pcb.123456/myfile".
7377 * If mkdtemp() is not available then 'name' is ignored and the
7378 * insecure tmpnam() function is used.
7380 * Files/names created with tempfile_name_new() should be unlinked
7381 * with tempfile_unlink to make sure the temporary directory is also
7382 * removed when mkdtemp() is used.
7385 tempfile_name_new (char * name
)
7387 char *tmpfile
= NULL
;
7389 char *tmpdir
, *mytmpdir
;
7393 assert ( name
!= NULL
);
7396 #define TEMPLATE "pcb.XXXXXXXX"
7399 tmpdir
= getenv ("TMPDIR");
7401 /* FIXME -- what about win32? */
7402 if (tmpdir
== NULL
) {
7406 mytmpdir
= (char *) malloc (sizeof(char) *
7411 if (mytmpdir
== NULL
) {
7412 fprintf (stderr
, "%s(): malloc failed()\n", __FUNCTION__
);
7417 (void)strcat (mytmpdir
, tmpdir
);
7418 (void)strcat (mytmpdir
, PCB_DIR_SEPARATOR_S
);
7419 (void)strcat (mytmpdir
, TEMPLATE
);
7420 if (mkdtemp (mytmpdir
) == NULL
) {
7421 fprintf (stderr
, "%s(): mkdtemp (\"%s\") failed\n", __FUNCTION__
, mytmpdir
);
7427 len
= strlen (mytmpdir
) + /* the temp directory name */
7428 1 + /* the directory sep. */
7429 strlen (name
) + /* the file name */
7430 1 /* the \0 termination */
7433 tmpfile
= (char *) malloc (sizeof (char) * len
);
7436 (void)strcat (tmpfile
, mytmpdir
);
7437 (void)strcat (tmpfile
, PCB_DIR_SEPARATOR_S
);
7438 (void)strcat (tmpfile
, name
);
7444 * tmpnam() uses a static buffer so strdup() the result right away
7445 * in case someone decides to create multiple temp names.
7447 tmpfile
= strdup (tmpnam (NULL
));
7450 /* Guile doesn't like \ separators */
7452 for (c
= tmpfile
; *c
; c
++)
7462 /* ---------------------------------------------------------------- */
7465 * \brief Unlink a temporary file.
7467 * If we have mkdtemp() then our temp file lives in a temporary
7468 * directory and we need to remove that directory too.
7471 tempfile_unlink (char * name
)
7474 /* SDB says: Want to keep old temp files for examiniation when debugging */
7483 /* it is possible that the file was never created so it is OK if the
7486 /* now figure out the directory name to remove */
7487 e
= strlen (name
) - 1;
7488 while (e
> 0 && name
[e
] != PCB_DIR_SEPARATOR_C
) {e
--;}
7490 dname
= strdup (name
);
7494 * at this point, e *should* point to the end of the directory part
7495 * but lets make sure.
7498 rc2
= rmdir (dname
);
7504 fprintf (stderr
, _("%s(): Unable to determine temp directory name from the temp file\n"),
7506 fprintf (stderr
, "%s(): \"%s\"\n",
7507 __FUNCTION__
, name
);
7511 /* name was allocated with malloc */
7516 * FIXME - should also return -1 if the temp file exists and was not
7524 int rc
= unlink (name
);
7527 fprintf (stderr
, _("Failed to unlink \"%s\"\n"), name
);
7538 /* ---------------------------------------------------------------- */
7539 static const char import_syntax
[] =
7541 "Import([gnetlist|make[,source,source,...]])\n"
7542 "Import(setnewpoint[,(mark|center|X,Y)])\n"
7543 "Import(setdisperse,D,units)\n");
7545 static const char import_help
[] = N_("Import schematics.");
7547 /* %start-doc actions Import
7549 Imports element and netlist data from the schematics (or some other
7550 source). The first parameter, which is optional, is the mode. If not
7551 specified, the @code{import::mode} attribute in the PCB is used.
7552 @code{gnetlist} means gnetlist is used to obtain the information from
7553 the schematics. @code{make} invokes @code{make}, assuming the user
7554 has a @code{Makefile} in the current directory. The @code{Makefile}
7555 will be invoked with the following variables set:
7560 The name of the .pcb file
7563 A space-separated list of source files
7566 The name of the file in which to put the command script, which may
7567 contain any @pcb{} actions. By default, this is a temporary file
7568 selected by @pcb{}, but if you specify an @code{import::outfile}
7569 attribute, that file name is used instead (and not automatically
7570 deleted afterwards).
7574 The target specified to be built is the first of these that apply:
7579 The target specified by an @code{import::target} attribute.
7582 The output file specified by an @code{import::outfile} attribute.
7585 If nothing else is specified, the target is @code{pcb_import}.
7589 If you specify an @code{import::makefile} attribute, then "-f <that
7590 file>" will be added to the command line.
7592 If you specify the mode, you may also specify the source files
7593 (schematics). If you do not specify any, the list of schematics is
7594 obtained by reading the @code{import::src@var{N}} attributes (like
7595 @code{import::src0}, @code{import::src1}, etc).
7597 For compatibility with future extensions to the import file format,
7598 the generated file @emph{must not} start with the two characters
7601 If a temporary file is needed the @code{TMPDIR} environment variable
7602 is used to select its location.
7604 Note that the programs @code{gnetlist} and @code{make} may be
7605 overridden by the user via the @code{make-program} and @code{gnetlist}
7606 @code{pcb} settings (i.e. in @code{~/.pcb/settings} or on the command
7609 If @pcb{} cannot determine which schematic(s) to import from, the GUI
7610 is called to let user choose (see @code{ImportGUI()}).
7612 Note that Import() doesn't delete anything - after an Import, elements
7613 which shouldn't be on the board are selected and may be removed once
7614 it's determined that the deletion is appropriate.
7616 If @code{Import()} is called with @code{setnewpoint}, then the location
7617 of new components can be specified. This is where parts show up when
7618 they're added to the board. The default is the center of the board.
7622 @item Import(setnewpoint)
7624 Prompts the user to click on the board somewhere, uses that point. If
7625 called by a hotkey, uses the current location of the crosshair.
7627 @item Import(setnewpoint,mark)
7629 Uses the location of the mark. If no mark is present, the point is
7632 @item Import(setnewpoint,center)
7634 Resets the point to the center of the board.
7636 @item Import(setnewpoint,X,Y,units)
7638 Sets the point to the specific coordinates given. Example:
7639 @code{Import(setnewpoint,50,25,mm)}
7643 Note that the X and Y locations are stored in attributes named
7644 @code{import::newX} and @code{import::newY} so you could change them
7645 manually if you wished.
7647 Calling @code{Import(setdisperse,D,units)} sets how much the newly
7648 placed elements are dispersed relative to the set point. For example,
7649 @code{Import(setdisperse,10,mm)} will offset each part randomly up to
7650 10mm away from the point. The default dispersion is 1/10th of the
7651 smallest board dimension. Dispersion is saved in the
7652 @code{import::disperse} attribute.
7657 ActionImport (int argc
, char **argv
, Coord x
, Coord y
)
7660 char **sources
= NULL
;
7664 printf("ActionImport: =========== Entering ActionImport ============\n");
7669 if (mode
&& strcasecmp (mode
, "setdisperse") == 0)
7678 const char *as
= AttributeGet (PCB
, "import::disperse");
7679 ds
= gui
->prompt_for(_("Enter dispersion:"), as
? as
: "0");
7683 sprintf(buf
, "%s%s", ds
, units
);
7684 AttributePut (PCB
, "import::disperse", buf
);
7687 AttributePut (PCB
, "import::disperse", ds
);
7688 if (ARG (1) == NULL
)
7693 if (mode
&& strcasecmp (mode
, "setnewpoint") == 0)
7695 const char *xs
, *ys
, *units
;
7705 gui
->get_coords (_("Click on a location"), &x
, &y
);
7707 else if (strcasecmp (xs
, "center") == 0)
7709 AttributeRemove (PCB
, "import::newX");
7710 AttributeRemove (PCB
, "import::newY");
7713 else if (strcasecmp (xs
, "mark") == 0)
7723 x
= GetValue (xs
, units
, NULL
);
7724 y
= GetValue (ys
, units
, NULL
);
7728 Message (_("Bad syntax for Import(setnewpoint)"));
7732 pcb_snprintf (buf
, sizeof (buf
), "%$ms", x
);
7733 AttributePut (PCB
, "import::newX", buf
);
7734 pcb_snprintf (buf
, sizeof (buf
), "%$ms", y
);
7735 AttributePut (PCB
, "import::newY", buf
);
7740 mode
= AttributeGet (PCB
, "import::mode");
7747 nsources
= argc
- 1;
7758 sprintf(sname
, "import::src%d", nsources
);
7759 src
= AttributeGet (PCB
, sname
);
7764 sources
= (char **) malloc ((nsources
+ 1) * sizeof (char *));
7768 sprintf(sname
, "import::src%d", nsources
);
7769 src
= AttributeGet (PCB
, sname
);
7770 sources
[nsources
] = src
;
7777 /* Replace .pcb with .sch and hope for the best. */
7778 char *pcbname
= PCB
->Filename
;
7780 char *dot
, *slash
, *bslash
;
7783 return hid_action("ImportGUI");
7785 schname
= (char *) malloc (strlen(pcbname
) + 5);
7786 strcpy (schname
, pcbname
);
7787 dot
= strchr (schname
, '.');
7788 slash
= strchr (schname
, '/');
7789 bslash
= strchr (schname
, '\\');
7790 if (dot
&& slash
&& dot
< slash
)
7792 if (dot
&& bslash
&& dot
< bslash
)
7796 strcat (schname
, ".sch");
7798 if (access (schname
, F_OK
))
7801 return hid_action("ImportGUI");
7804 sources
= (char **) malloc (2 * sizeof (char *));
7805 sources
[0] = schname
;
7810 if (strcasecmp (mode
, "gnetlist") == 0)
7812 char *tmpfile
= tempfile_name_new ("gnetlist_output");
7816 if (tmpfile
== NULL
) {
7817 Message (_("Could not create temp file"));
7821 cmd
= (char **) malloc ((7 + nsources
) * sizeof (char *));
7822 cmd
[0] = Settings
.GnetlistProgram
;
7828 for (i
=0; i
<nsources
; i
++)
7829 cmd
[6+i
] = sources
[i
];
7830 cmd
[6+nsources
] = NULL
;
7833 printf("ActionImport: =========== About to run gnetlist ============\n");
7834 printf("%s %s %s %s %s %s %s ...\n",
7835 cmd
[0], cmd
[1], cmd
[2], cmd
[3], cmd
[4], cmd
[5], cmd
[6]);
7838 if (pcb_spawnvp (cmd
))
7845 printf("ActionImport: =========== About to run ActionExecuteFile, file = %s ============\n", tmpfile
);
7850 ActionExecuteFile (1, cmd
, 0, 0);
7853 tempfile_unlink (tmpfile
);
7855 else if (strcasecmp (mode
, "make") == 0)
7857 int must_free_tmpfile
= 0;
7863 char *user_outfile
= NULL
;
7864 char *user_makefile
= NULL
;
7865 char *user_target
= NULL
;
7868 user_outfile
= AttributeGet (PCB
, "import::outfile");
7869 user_makefile
= AttributeGet (PCB
, "import::makefile");
7870 user_target
= AttributeGet (PCB
, "import::target");
7871 if (user_outfile
&& !user_target
)
7872 user_target
= user_outfile
;
7875 tmpfile
= user_outfile
;
7878 tmpfile
= tempfile_name_new ("gnetlist_output");
7879 if (tmpfile
== NULL
) {
7880 Message (_("Could not create temp file"));
7884 must_free_tmpfile
= 1;
7887 srclen
= sizeof("SRCLIST=") + 2;
7888 for (i
=0; i
<nsources
; i
++)
7889 srclen
+= strlen (sources
[i
]) + 2;
7890 srclist
= (char *) malloc (srclen
);
7891 strcpy (srclist
, "SRCLIST=");
7892 for (i
=0; i
<nsources
; i
++)
7895 strcat (srclist
, " ");
7896 strcat (srclist
, sources
[i
]);
7899 cmd
[0] = Settings
.MakeProgram
;
7901 cmd
[2] = Concat ("PCB=", PCB
->Filename
, NULL
);
7903 cmd
[4] = Concat ("OUT=", tmpfile
, NULL
);
7908 cmd
[i
++] = user_makefile
;
7910 cmd
[i
++] = user_target
? user_target
: (char *)"pcb_import";
7913 if (pcb_spawnvp (cmd
))
7915 if (must_free_tmpfile
)
7925 ActionExecuteFile (1, cmd
, 0, 0);
7930 if (must_free_tmpfile
)
7931 tempfile_unlink (tmpfile
);
7935 Message (_("Unknown import mode: %s\n"), mode
);
7940 AddAllRats (false, NULL
);
7943 printf("ActionImport: =========== Leaving ActionImport ============\n");
7949 /* ------------------------------------------------------------ */
7951 static const char attributes_syntax
[] =
7952 N_("Attributes(Layout|Layer|Element)\n"
7953 "Attributes(Layer,layername)");
7955 static const char attributes_help
[] =
7956 N_("Let the user edit the attributes of the layout, current or given\n"
7957 "layer, or selected element.");
7959 /* %start-doc actions Attributes
7961 This just pops up a dialog letting the user edit the attributes of the
7962 pcb, an element, or a layer.
7968 ActionAttributes (int argc
, char **argv
, Coord x
, Coord y
)
7970 char *function
= ARG (0);
7971 char *layername
= ARG (1);
7977 if (!gui
->edit_attributes
)
7979 Message (_("This GUI doesn't support Attribute Editing\n"));
7983 switch (GetFunctionID (function
))
7987 gui
->edit_attributes(_("Layout Attributes"), &(PCB
->Attributes
));
7993 LayerType
*layer
= CURRENT
;
7998 for (i
=0; i
<max_copper_layer
; i
++)
7999 if (strcmp (PCB
->Data
->Layer
[i
].Name
, layername
) == 0)
8001 layer
= & (PCB
->Data
->Layer
[i
]);
8006 Message (_("No layer named %s\n"), layername
);
8010 buf
= (char *) malloc (strlen (layer
->Name
) +
8011 strlen (_("Layer %s Attributes")));
8012 sprintf (buf
, _("Layer %s Attributes"), layer
->Name
);
8013 gui
->edit_attributes(buf
, &(layer
->Attributes
));
8021 ElementType
*e
= NULL
;
8022 ELEMENT_LOOP (PCB
->Data
);
8024 if (TEST_FLAG (SELECTEDFLAG
, element
))
8033 Message (_("Too many elements selected\n"));
8039 gui
->get_coords (_("Click on an element"), &x
, &y
);
8041 (x
, y
, ELEMENT_TYPE
, &ptrtmp
,
8042 &ptrtmp
, &ptrtmp
)) != NO_TYPE
)
8043 e
= (ElementType
*) ptrtmp
;
8046 Message (_("No element found there\n"));
8051 if (NAMEONPCB_NAME(e
))
8053 buf
= (char *) malloc (strlen (NAMEONPCB_NAME(e
)) +
8054 strlen (_("Element %s Attributes")));
8055 sprintf(buf
, _("Element %s Attributes"), NAMEONPCB_NAME(e
));
8059 buf
= strdup (_("Unnamed Element Attributes"));
8061 gui
->edit_attributes(buf
, &(e
->Attributes
));
8073 /* --------------------------------------------------------------------------- */
8075 HID_Action action_action_list
[] = {
8076 {"AddRats", 0, ActionAddRats
,
8077 addrats_help
, addrats_syntax
}
8079 {"Attributes", 0, ActionAttributes
,
8080 attributes_help
, attributes_syntax
}
8082 {"Atomic", 0, ActionAtomic
,
8083 atomic_help
, atomic_syntax
}
8085 {"AutoPlaceSelected", 0, ActionAutoPlaceSelected
,
8086 autoplace_help
, autoplace_syntax
}
8088 {"AutoRoute", 0, ActionAutoRoute
,
8089 autoroute_help
, autoroute_syntax
}
8091 {"ChangeClearSize", 0, ActionChangeClearSize
,
8092 changeclearsize_help
, changeclearsize_syntax
}
8094 {"ChangeDrillSize", 0, ActionChange2ndSize
,
8095 changedrillsize_help
, changedrillsize_syntax
}
8097 {"ChangeHole", 0, ActionChangeHole
,
8098 changehold_help
, changehold_syntax
}
8100 {"ChangeJoin", 0, ActionChangeJoin
,
8101 changejoin_help
, changejoin_syntax
}
8103 {"ChangeName", 0, ActionChangeName
,
8104 changename_help
, changename_syntax
}
8106 {"ChangePaste", 0, ActionChangePaste
,
8107 changepaste_help
, changepaste_syntax
}
8109 {"ChangePinName", 0, ActionChangePinName
,
8110 changepinname_help
, changepinname_syntax
}
8112 {"ChangeSize", 0, ActionChangeSize
,
8113 changesize_help
, changesize_syntax
}
8115 {"ChangeSquare", 0, ActionChangeSquare
,
8116 changesquare_help
, changesquare_syntax
}
8118 {"ChangeOctagon", 0, ActionChangeOctagon
,
8119 changeoctagon_help
, changeoctagon_syntax
}
8121 {"ClearSquare", 0, ActionClearSquare
,
8122 clearsquare_help
, clearsquare_syntax
}
8124 {"ClearOctagon", 0, ActionClearOctagon
,
8125 clearoctagon_help
, clearoctagon_syntax
}
8127 {"Connection", 0, ActionConnection
,
8128 connection_help
, connection_syntax
}
8130 {"Delete", 0, ActionDelete
,
8131 delete_help
, delete_syntax
}
8133 {"DeleteRats", 0, ActionDeleteRats
,
8134 deleterats_help
, deleterats_syntax
}
8136 {"DisperseElements", 0, ActionDisperseElements
,
8137 disperseelements_help
, disperseelements_syntax
}
8139 {"Display", 0, ActionDisplay
,
8140 display_help
, display_syntax
}
8142 {"DRC", 0, ActionDRCheck
,
8143 drc_help
, drc_syntax
}
8145 {"DumpLibrary", 0, ActionDumpLibrary
,
8146 dumplibrary_help
, dumplibrary_syntax
}
8148 {"ExecuteFile", 0, ActionExecuteFile
,
8149 executefile_help
, executefile_syntax
}
8151 {"Flip", N_("Click on Object or Flip Point"), ActionFlip
,
8152 flip_help
, flip_syntax
}
8154 {"LoadFrom", 0, ActionLoadFrom
,
8155 loadfrom_help
, loadfrom_syntax
}
8157 {"MarkCrosshair", 0, ActionMarkCrosshair
,
8158 markcrosshair_help
, markcrosshair_syntax
}
8160 {"Message", 0, ActionMessage
,
8161 message_help
, message_syntax
}
8163 {"MinMaskGap", 0, ActionMinMaskGap
,
8164 minmaskgap_help
, minmaskgap_syntax
}
8166 {"MinClearGap", 0, ActionMinClearGap
,
8167 mincleargap_help
, mincleargap_syntax
}
8169 {"Mode", 0, ActionMode
,
8170 mode_help
, mode_syntax
}
8172 {"MorphPolygon", 0, ActionMorphPolygon
,
8173 morphpolygon_help
, morphpolygon_syntax
}
8175 {"PasteBuffer", 0, ActionPasteBuffer
,
8176 pastebuffer_help
, pastebuffer_syntax
}
8178 {"Quit", 0, ActionQuit
,
8179 quit_help
, quit_syntax
}
8181 {"RemoveSelected", 0, ActionRemoveSelected
,
8182 removeselected_help
, removeselected_syntax
}
8184 {"Renumber", 0, ActionRenumber
,
8185 renumber_help
, renumber_syntax
}
8187 {"RipUp", 0, ActionRipUp
,
8188 ripup_help
, ripup_syntax
}
8190 {"Select", 0, ActionSelect
,
8191 select_help
, select_syntax
}
8193 {"Unselect", 0, ActionUnselect
,
8194 unselect_help
, unselect_syntax
}
8196 {"SaveSettings", 0, ActionSaveSettings
,
8197 savesettings_help
, savesettings_syntax
}
8199 {"SaveTo", 0, ActionSaveTo
,
8200 saveto_help
, saveto_syntax
}
8202 {"SetSquare", 0, ActionSetSquare
,
8203 setsquare_help
, setsquare_syntax
}
8205 {"SetOctagon", 0, ActionSetOctagon
,
8206 setoctagon_help
, setoctagon_syntax
}
8208 {"SetThermal", 0, ActionSetThermal
,
8209 setthermal_help
, setthermal_syntax
}
8211 {"SetValue", 0, ActionSetValue
,
8212 setvalue_help
, setvalue_syntax
}
8214 {"ToggleHideName", 0, ActionToggleHideName
,
8215 togglehidename_help
, togglehidename_syntax
}
8217 {"Undo", 0, ActionUndo
,
8218 undo_help
, undo_syntax
}
8220 {"Redo", 0, ActionRedo
,
8221 redo_help
, redo_syntax
}
8223 {"SetSame", N_("Select item to use attributes from"), ActionSetSame
,
8224 setsame_help
, setsame_syntax
}
8226 {"SetFlag", 0, ActionSetFlag
,
8227 setflag_help
, setflag_syntax
}
8229 {"ClrFlag", 0, ActionClrFlag
,
8230 clrflag_help
, clrflag_syntax
}
8232 {"ChangeFlag", 0, ActionChangeFlag
,
8233 changeflag_help
, changeflag_syntax
}
8235 {"Polygon", 0, ActionPolygon
,
8236 polygon_help
, polygon_syntax
}
8238 {"RouteStyle", 0, ActionRouteStyle
,
8239 routestyle_help
, routestyle_syntax
}
8241 {"MoveObject", N_("Select an Object"), ActionMoveObject
,
8242 moveobject_help
, moveobject_syntax
}
8244 {"MoveToCurrentLayer", 0, ActionMoveToCurrentLayer
,
8245 movetocurrentlayer_help
, movetocurrentlayer_syntax
}
8247 {"New", 0, ActionNew
,
8248 new_help
, new_syntax
}
8250 {"pscalib", 0, ActionPSCalib
}
8252 {"ElementList", 0, ActionElementList
,
8253 elementlist_help
, elementlist_syntax
}
8255 {"ElementSetAttr", 0, ActionElementSetAttr
,
8256 elementsetattr_help
, elementsetattr_syntax
}
8258 {"ExecCommand", 0, ActionExecCommand
,
8259 execcommand_help
, execcommand_syntax
}
8261 {"Import", 0, ActionImport
,
8262 import_help
, import_syntax
}
8266 REGISTER_ACTIONS (action_action_list
)