Merge the usermenu branch. This reworks how the menus and hotkeys
[geda-pcb/pcjc2.git] / src / action.c
blob4d05947d0274763d6c43116e0685ae5619b82353
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 Thomas Nau
8 * Copyright (C) 1997, 1998, 1999, 2000, 2001 Harry Eaton
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * Contact addresses for paper mail and Email:
25 * Harry Eaton, 6697 Buttonhole Ct, Columbia, MD 21044, USA
26 * haceaton@aplcomm.jhuapl.edu
30 /* action routines for output window
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
37 #include "global.h"
39 #include "action.h"
40 #include "autoplace.h"
41 #include "autoroute.h"
42 #include "buffer.h"
43 #include "change.h"
44 #include "command.h"
45 #include "copy.h"
46 #include "create.h"
47 #include "crosshair.h"
48 #include "data.h"
49 #include "draw.h"
50 #include "error.h"
51 #include "file.h"
52 #include "find.h"
53 #include "insert.h"
54 #include "line.h"
55 #include "mymem.h"
56 #include "misc.h"
57 #include "move.h"
58 #include "polygon.h"
59 /*#include "print.h"*/
60 #include "rats.h"
61 #include "remove.h"
62 #include "report.h"
63 #include "rotate.h"
64 #include "rubberband.h"
65 #include "search.h"
66 #include "select.h"
67 #include "set.h"
68 #include "thermal.h"
69 #include "undo.h"
70 #include "rtree.h"
72 #ifdef HAVE_LIBDMALLOC
73 #include <dmalloc.h>
74 #endif
76 RCSID ("$Id$");
78 /* ---------------------------------------------------------------------------
79 * some local types
81 typedef enum
83 F_AddSelected,
84 F_All,
85 F_AllConnections,
86 F_AllRats,
87 F_AllUnusedPins,
88 F_Arc,
89 F_Arrow,
90 F_Block,
91 F_Description,
92 F_Cancel,
93 F_Center,
94 F_Clear,
95 F_ClearAndRedraw,
96 F_ClearList,
97 F_Close,
98 F_Connection,
99 F_Convert,
100 F_Copy,
101 F_CycleClip,
102 F_DeleteRats,
103 F_Drag,
104 F_DrillReport,
105 F_Element,
106 F_ElementByName,
107 F_ElementConnections,
108 F_ElementToBuffer,
109 F_Escape,
110 F_Find,
111 F_FlipElement,
112 F_FoundPins,
113 F_Grid,
114 F_InsertPoint,
115 F_Layer,
116 F_Layout,
117 F_LayoutAs,
118 F_LayoutToBuffer,
119 F_Line,
120 F_LineSize,
121 F_Lock,
122 F_Mirror,
123 F_Move,
124 F_NameOnPCB,
125 F_Netlist,
126 F_None,
127 F_Notify,
128 F_Object,
129 F_ObjectByName,
130 F_PasteBuffer,
131 F_PadByName,
132 F_PinByName,
133 F_PinOrPadName,
134 F_Pinout,
135 F_Polygon,
136 F_PreviousPoint,
137 F_RatsNest,
138 F_Rectangle,
139 F_Redraw,
140 F_Release,
141 F_Revert,
142 F_Remove,
143 F_RemoveSelected,
144 F_Report,
145 F_Reset,
146 F_ResetLinesAndPolygons,
147 F_ResetPinsViasAndPads,
148 F_Restore,
149 F_Rotate,
150 F_Save,
151 F_Scroll,
152 F_Selected,
153 F_SelectedArcs,
154 F_SelectedElements,
155 F_SelectedLines,
156 F_SelectedNames,
157 F_SelectedObjects,
158 F_SelectedPads,
159 F_SelectedPins,
160 F_SelectedTexts,
161 F_SelectedVias,
162 F_SelectedRats,
163 F_Stroke,
164 F_Text,
165 F_TextByName,
166 F_TextScale,
167 F_Thermal,
168 F_ToLayout,
169 F_ToggleAllDirections,
170 F_ToggleAutoDRC,
171 F_ToggleClearLine,
172 F_ToggleGrid,
173 F_ToggleMask,
174 F_ToggleName,
175 F_ToggleObject,
176 F_ToggleShowDRC,
177 F_ToggleLiveRoute,
178 F_ToggleRubberBandMode,
179 F_ToggleStartDirection,
180 F_ToggleSnapPin,
181 F_ToggleThindraw,
182 F_ToggleLockNames,
183 F_ToggleOnlyNames,
184 F_ToggleThindrawPoly,
185 F_ToggleOrthoMove,
186 F_ToggleLocalRef,
187 F_ToggleCheckPlanes,
188 F_ToggleUniqueNames,
189 F_Via,
190 F_ViaByName,
191 F_Value,
192 F_ViaDrillingHole,
193 F_ViaSize,
194 F_Zoom
196 FunctionID;
198 typedef struct /* used to identify subfunctions */
200 char *Identifier;
201 FunctionID ID;
203 FunctionType, *FunctionTypePtr;
205 /* --------------------------------------------------------------------------- */
207 /* %start-doc actions 00delta
209 Many actions take a @code{delta} parameter as the last parameter,
210 which is an amount to change something. That @code{delta} may include
211 units, as an additional parameter, such as @code{Action(Object,5,mm)}.
212 If no units are specified, the default is PCB's native units
213 (currently 1/100 mil). Also, if the delta is prefixed by @code{+} or
214 @code{-}, the size is increased or decreased by that amount.
215 Otherwise, the size size is set to the given amount.
217 @example
218 Action(Object,5,mil)
219 Action(Object,+0.5,mm)
220 Action(Object,-1)
221 @end example
223 Actions which take a @code{delta} parameter which do not accept all
224 these options will specify what they do take.
226 %end-doc */
228 /* %start-doc actions 00objects
230 Many actions act on indicated objects on the board. They will have
231 parameters like @code{ToggleObject} or @code{SelectedVias} to indicate
232 what group of objects they act on. Unless otherwise specified, these
233 parameters are defined as follows:
235 @table @code
237 @item Object
238 @itemx ToggleObject
239 Affects the object under the mouse pointer. If this action is invoked
240 from a menu or script, the user will be prompted to click on an
241 object, which is then the object affected.
243 @item Selected
244 @itemx SelectedObjects
246 Affects all objects which are currently selected. At least, all
247 selected objects for which the given action makes sense.
249 @item SelectedPins
250 @itemx SelectedVias
251 @itemx Selected@var{Type}
252 @itemx @i{etc}
253 Affects all objects which are both selected and of the @var{Type} specified.
255 @end table
257 %end-doc */
259 /* %start-doc actions 00macros
261 @macro pinshapes
263 Pins, pads, and vias can have various shapes. All may be round. Pins
264 and pads may be square (obviously "square" pads are usually
265 rectangular). Pins and vias may be octagonal. When you change a
266 shape flag of an element, you actually change all of its pins and
267 pads.
269 Note that the square flag takes precedence over the octagon flag,
270 thus, if both the square and octagon flags are set, the object is
271 square. When the square flag is cleared, the pins and pads will be
272 either round or, if the octagon flag is set, octagonal.
274 @end macro
276 %end-doc */
278 /* ---------------------------------------------------------------------------
279 * some local identifiers
281 static PointType InsertedPoint;
282 static LayerTypePtr lastLayer;
283 static struct
285 PolygonTypePtr poly;
286 LineType line;
288 fake;
290 static struct
292 int X;
293 int Y;
294 Cardinal Buffer;
295 Boolean Click;
296 Boolean Moving; /* selected type clicked on */
297 int Hit; /* move type clicked on */
298 void *ptr1;
299 void *ptr2;
300 void *ptr3;
302 Note;
304 static Cardinal polyIndex = 0;
305 static Boolean IgnoreMotionEvents = False;
306 static Boolean saved_mode = False;
307 #ifdef HAVE_LIBSTROKE
308 static Boolean mid_stroke = False;
309 static BoxType StrokeBox;
310 #endif
311 static FunctionType Functions[] = {
312 {"AddSelected", F_AddSelected},
313 {"All", F_All},
314 {"AllConnections", F_AllConnections},
315 {"AllRats", F_AllRats},
316 {"AllUnusedPins", F_AllUnusedPins},
317 {"Arc", F_Arc},
318 {"Arrow", F_Arrow},
319 {"Block", F_Block},
320 {"Description", F_Description},
321 {"Cancel", F_Cancel},
322 {"Center", F_Center},
323 {"Clear", F_Clear},
324 {"ClearAndRedraw", F_ClearAndRedraw},
325 {"ClearList", F_ClearList},
326 {"Close", F_Close},
327 {"Connection", F_Connection},
328 {"Convert", F_Convert},
329 {"Copy", F_Copy},
330 {"CycleClip", F_CycleClip},
331 {"DeleteRats", F_DeleteRats},
332 {"Drag", F_Drag},
333 {"DrillReport", F_DrillReport},
334 {"Element", F_Element},
335 {"ElementByName", F_ElementByName},
336 {"ElementConnections", F_ElementConnections},
337 {"ElementToBuffer", F_ElementToBuffer},
338 {"Escape", F_Escape},
339 {"Find", F_Find},
340 {"FlipElement", F_FlipElement},
341 {"FoundPins", F_FoundPins},
342 {"Grid", F_Grid},
343 {"InsertPoint", F_InsertPoint},
344 {"Layer", F_Layer},
345 {"Layout", F_Layout},
346 {"LayoutAs", F_LayoutAs},
347 {"LayoutToBuffer", F_LayoutToBuffer},
348 {"Line", F_Line},
349 {"LineSize", F_LineSize},
350 {"Lock", F_Lock},
351 {"Mirror", F_Mirror},
352 {"Move", F_Move},
353 {"NameOnPCB", F_NameOnPCB},
354 {"Netlist", F_Netlist},
355 {"None", F_None},
356 {"Notify", F_Notify},
357 {"Object", F_Object},
358 {"ObjectByName", F_ObjectByName},
359 {"PasteBuffer", F_PasteBuffer},
360 {"PadByName", F_PadByName},
361 {"PinByName", F_PinByName},
362 {"PinOrPadName", F_PinOrPadName},
363 {"Pinout", F_Pinout},
364 {"Polygon", F_Polygon},
365 {"PreviousPoint", F_PreviousPoint},
366 {"RatsNest", F_RatsNest},
367 {"Rectangle", F_Rectangle},
368 {"Redraw", F_Redraw},
369 {"Release", F_Release},
370 {"Remove", F_Remove},
371 {"RemoveSelected", F_RemoveSelected},
372 {"Report", F_Report},
373 {"Reset", F_Reset},
374 {"ResetLinesAndPolygons", F_ResetLinesAndPolygons},
375 {"ResetPinsViasAndPads", F_ResetPinsViasAndPads},
376 {"Restore", F_Restore},
377 {"Revert", F_Revert},
378 {"Rotate", F_Rotate},
379 {"Save", F_Save},
380 {"Scroll", F_Scroll},
381 {"Selected", F_Selected},
382 {"SelectedArcs", F_SelectedArcs},
383 {"SelectedElements", F_SelectedElements},
384 {"SelectedLines", F_SelectedLines},
385 {"SelectedNames", F_SelectedNames},
386 {"SelectedObjects", F_SelectedObjects},
387 {"SelectedPins", F_SelectedPins},
388 {"SelectedPads", F_SelectedPads},
389 {"SelectedRats", F_SelectedRats},
390 {"SelectedTexts", F_SelectedTexts},
391 {"SelectedVias", F_SelectedVias},
392 {"Stroke", F_Stroke},
393 {"Text", F_Text},
394 {"TextByName", F_TextByName},
395 {"TextScale", F_TextScale},
396 {"Thermal", F_Thermal},
397 {"ToLayout", F_ToLayout},
398 {"Toggle45Degree", F_ToggleAllDirections},
399 {"ToggleClearLine", F_ToggleClearLine},
400 {"ToggleGrid", F_ToggleGrid},
401 {"ToggleMask", F_ToggleMask},
402 {"ToggleName", F_ToggleName},
403 {"ToggleObject", F_ToggleObject},
404 {"ToggleRubberBandMode", F_ToggleRubberBandMode},
405 {"ToggleStartDirection", F_ToggleStartDirection},
406 {"ToggleSnapPin", F_ToggleSnapPin},
407 {"ToggleThindraw", F_ToggleThindraw},
408 {"ToggleThindrawPoly", F_ToggleThindrawPoly},
409 {"ToggleLockNames", F_ToggleLockNames},
410 {"ToggleOnlyNames", F_ToggleOnlyNames},
411 {"ToggleCheckPlanes", F_ToggleCheckPlanes},
412 {"ToggleLocalRef", F_ToggleLocalRef},
413 {"ToggleOrthoMove", F_ToggleOrthoMove},
414 {"ToggleShowDRC", F_ToggleShowDRC},
415 {"ToggleLiveRoute", F_ToggleLiveRoute},
416 {"ToggleAutoDRC", F_ToggleAutoDRC},
417 {"ToggleUniqueNames", F_ToggleUniqueNames},
418 {"Value", F_Value},
419 {"Via", F_Via},
420 {"ViaByName", F_ViaByName},
421 {"ViaSize", F_ViaSize},
422 {"ViaDrillingHole", F_ViaDrillingHole},
423 {"Zoom", F_Zoom}
426 /* ---------------------------------------------------------------------------
427 * some local routines
429 static int GetFunctionID (String);
430 static void AdjustAttachedBox (void);
431 static void NotifyLine (void);
432 static void NotifyBlock (void);
433 static void NotifyMode (void);
434 static void ClearWarnings (void);
435 #ifdef HAVE_LIBSTROKE
436 static void FinishStroke (void);
437 extern void stroke_init (void);
438 extern void stroke_record (int x, int y);
439 extern int stroke_trans (char *s);
440 #endif
441 static void ChangeFlag (char *, char *, int, char *);
443 #define ARG(n) (argc > (n) ? argv[n] : 0)
445 #ifdef HAVE_LIBSTROKE
447 /* ---------------------------------------------------------------------------
448 * FinishStroke - try to recognize the stroke sent
450 void
451 FinishStroke (void)
453 char msg[255];
454 int type;
455 unsigned long num;
456 void *ptr1, *ptr2, *ptr3;
458 mid_stroke = False;
459 if (stroke_trans (msg))
461 num = atoi (msg);
462 switch (num)
464 case 456:
465 if (Settings.Mode == LINE_MODE)
467 SetMode (LINE_MODE);
469 break;
470 case 9874123:
471 case 74123:
472 case 987412:
473 case 8741236:
474 case 874123:
475 RotateScreenObject (StrokeBox.X1, StrokeBox.Y1, SWAP_IDENT ? 1 : 3);
476 break;
477 case 7896321:
478 case 786321:
479 case 789632:
480 case 896321:
481 RotateScreenObject (StrokeBox.X1, StrokeBox.Y1, SWAP_IDENT ? 3 : 1);
482 break;
483 case 258:
484 SetMode (LINE_MODE);
485 break;
486 case 852:
487 SetMode (ARROW_MODE);
488 break;
489 case 1478963:
490 ActionUndo ("");
491 break;
492 case 147423:
493 case 147523:
494 case 1474123:
495 Redo (True);
496 break;
497 case 148963:
498 case 147863:
499 case 147853:
500 case 145863:
501 SetMode (VIA_MODE);
502 break;
503 case 951:
504 case 9651:
505 case 9521:
506 case 9621:
507 case 9851:
508 case 9541:
509 case 96521:
510 case 96541:
511 case 98541:
512 SetZoom (1000); /* special zoom extents */
513 break;
514 case 159:
515 case 1269:
516 case 1259:
517 case 1459:
518 case 1569:
519 case 1589:
520 case 12569:
521 case 12589:
522 case 14589:
524 LocationType x = (StrokeBox.X1 + StrokeBox.X2) / 2;
525 LocationType y = (StrokeBox.Y1 + StrokeBox.Y2) / 2;
526 int z;
529 log (fabs (StrokeBox.X2 - StrokeBox.X1) / Output.Width) /
530 log (2.0);
532 MAX (z,
534 log (fabs (StrokeBox.Y2 - StrokeBox.Y1) / Output.Height) /
535 log (2.0));
536 SetZoom (z);
538 CenterDisplay (x, y, False);
539 break;
542 default:
543 Message ("Unknown stroke %s\n", msg);
544 break;
547 else
548 gui->beep ();
550 #endif
552 /* ---------------------------------------------------------------------------
553 * Clear warning color from pins/pads
555 static void
556 ClearWarnings ()
558 Settings.RatWarn = False;
559 ALLPIN_LOOP (PCB->Data);
561 if (TEST_FLAG (WARNFLAG, pin))
563 CLEAR_FLAG (WARNFLAG, pin);
564 DrawPin (pin, 0);
567 ENDALL_LOOP;
568 ALLPAD_LOOP (PCB->Data);
570 if (TEST_FLAG (WARNFLAG, pad))
572 CLEAR_FLAG (WARNFLAG, pad);
573 DrawPad (pad, 0);
576 ENDALL_LOOP;
577 Draw ();
580 static void
581 click_cb (hidval hv)
583 if (Note.Click)
585 Note.Click = False;
586 if (Note.Moving && !gui->shift_is_pressed ())
588 HideCrosshair (True);
589 Note.Buffer = Settings.BufferNumber;
590 SetBufferNumber (MAX_BUFFER - 1);
591 ClearBuffer (PASTEBUFFER);
592 AddSelectedToBuffer (PASTEBUFFER, Note.X, Note.Y, True);
593 SaveUndoSerialNumber ();
594 RemoveSelected ();
595 SaveMode ();
596 saved_mode = True;
597 SetMode (PASTEBUFFER_MODE);
598 RestoreCrosshair (True);
600 else if (Note.Hit && !gui->shift_is_pressed ())
602 HideCrosshair (True);
603 SaveMode ();
604 saved_mode = True;
605 SetMode (gui->control_is_pressed ()? COPY_MODE : MOVE_MODE);
606 Crosshair.AttachedObject.Ptr1 = Note.ptr1;
607 Crosshair.AttachedObject.Ptr2 = Note.ptr2;
608 Crosshair.AttachedObject.Ptr3 = Note.ptr3;
609 Crosshair.AttachedObject.Type = Note.Hit;
610 AttachForCopy (Note.X, Note.Y);
611 RestoreCrosshair (True);
613 else
615 BoxType box;
617 Note.Hit = 0;
618 Note.Moving = False;
619 HideCrosshair (True);
620 SaveUndoSerialNumber ();
621 box.X1 = -MAX_COORD;
622 box.Y1 = -MAX_COORD;
623 box.X2 = MAX_COORD;
624 box.Y2 = MAX_COORD;
625 /* unselect first if shift key not down */
626 if (!gui->shift_is_pressed () && SelectBlock (&box, False))
627 SetChangedFlag (True);
628 NotifyBlock ();
629 Crosshair.AttachedBox.Point1.X = Note.X;
630 Crosshair.AttachedBox.Point1.Y = Note.Y;
631 RestoreCrosshair (True);
636 static void
637 ReleaseMode (void)
639 BoxType box;
641 if (Note.Click)
643 BoxType box;
645 box.X1 = -MAX_COORD;
646 box.Y1 = -MAX_COORD;
647 box.X2 = MAX_COORD;
648 box.Y2 = MAX_COORD;
650 Note.Click = False; /* inhibit timer action */
651 SaveUndoSerialNumber ();
652 /* unselect first if shift key not down */
653 if (!gui->shift_is_pressed ())
655 if (SelectBlock (&box, False))
656 SetChangedFlag (True);
657 if (Note.Moving)
659 Note.Moving = 0;
660 Note.Hit = 0;
661 return;
664 RestoreUndoSerialNumber ();
665 if (SelectObject ())
666 SetChangedFlag (True);
667 Note.Hit = 0;
668 Note.Moving = 0;
670 else if (Note.Moving)
672 RestoreUndoSerialNumber ();
673 NotifyMode ();
674 ClearBuffer (PASTEBUFFER);
675 SetBufferNumber (Note.Buffer);
676 Note.Moving = False;
677 Note.Hit = 0;
679 else if (Note.Hit)
681 NotifyMode ();
682 Note.Hit = 0;
684 else if (Settings.Mode == ARROW_MODE)
686 box.X1 = MIN (Crosshair.AttachedBox.Point1.X,
687 Crosshair.AttachedBox.Point2.X);
688 box.Y1 = MIN (Crosshair.AttachedBox.Point1.Y,
689 Crosshair.AttachedBox.Point2.Y);
690 box.X2 = MAX (Crosshair.AttachedBox.Point1.X,
691 Crosshair.AttachedBox.Point2.X);
692 box.Y2 = MAX (Crosshair.AttachedBox.Point1.Y,
693 Crosshair.AttachedBox.Point2.Y);
694 RestoreUndoSerialNumber ();
695 if (SelectBlock (&box, True))
696 SetChangedFlag (True);
697 else if (Bumped)
698 IncrementUndoSerialNumber ();
699 Crosshair.AttachedBox.State = STATE_FIRST;
701 if (saved_mode)
702 RestoreMode ();
703 saved_mode = False;
706 /* ---------------------------------------------------------------------------
707 * get function ID of passed string
709 #define HSIZE 257
710 static char function_hash[HSIZE];
711 static int hash_initted = 0;
713 static int
714 hashfunc(String s)
716 int i = 0;
717 while (*s)
719 i ^= i >> 16;
720 i = (i * 13) ^ (unsigned char)tolower(*s);
721 s ++;
723 i = (unsigned int)i % HSIZE;
724 return i;
727 static int
728 GetFunctionID (String Ident)
730 int i, h;
732 if (!hash_initted)
734 hash_initted = 1;
735 if (HSIZE < ENTRIES (Functions) * 2)
737 fprintf(stderr, "Error: function hash size too small (%d vs %ld at %s:%d)\n",
738 HSIZE, ENTRIES (Functions)*2, __FILE__, __LINE__);
739 exit(1);
741 if (ENTRIES (Functions) > 254)
743 /* Change 'char' to 'int' and remove this when we get to 256
744 strings to hash. */
745 fprintf(stderr, "Error: function hash type too small (%d vs %ld at %s:%d)\n",
746 256, ENTRIES (Functions), __FILE__, __LINE__);
747 exit(1);
750 for (i=ENTRIES (Functions)-1; i>=0; i--)
752 h = hashfunc (Functions[i].Identifier);
753 while (function_hash[h])
754 h = (h + 1) % HSIZE;
755 function_hash[h] = i + 1;
759 i = hashfunc (Ident);
760 while (1)
762 /* We enforce the "hash table bigger than function table" rule,
763 so we know there will be at least one zero entry to find. */
764 if (!function_hash[i])
765 return (-1);
766 if (!strcasecmp (Ident, Functions[function_hash[i]-1].Identifier))
767 return ((int) Functions[function_hash[i]-1].ID);
768 i ++;
772 /* ---------------------------------------------------------------------------
773 * set new coordinates if in 'RECTANGLE' mode
774 * the cursor shape is also adjusted
776 static void
777 AdjustAttachedBox (void)
779 if (Settings.Mode == ARC_MODE)
781 Crosshair.AttachedBox.otherway = gui->shift_is_pressed ();
782 return;
784 switch (Crosshair.AttachedBox.State)
786 case STATE_SECOND: /* one corner is selected */
788 /* update coordinates */
789 Crosshair.AttachedBox.Point2.X = Crosshair.X;
790 Crosshair.AttachedBox.Point2.Y = Crosshair.Y;
791 break;
796 /* ---------------------------------------------------------------------------
797 * adjusts the objects which are to be created like attached lines...
799 void
800 AdjustAttachedObjects (void)
802 PointTypePtr pnt;
803 switch (Settings.Mode)
805 /* update at least an attached block (selection) */
806 case NO_MODE:
807 case ARROW_MODE:
808 if (Crosshair.AttachedBox.State)
810 Crosshair.AttachedBox.Point2.X = Crosshair.X;
811 Crosshair.AttachedBox.Point2.Y = Crosshair.Y;
813 break;
815 /* rectangle creation mode */
816 case RECTANGLE_MODE:
817 case ARC_MODE:
818 AdjustAttachedBox ();
819 break;
821 /* polygon creation mode */
822 case POLYGON_MODE:
823 AdjustAttachedLine ();
824 break;
825 /* line creation mode */
826 case LINE_MODE:
827 if (PCB->RatDraw || PCB->Clipping == 0)
828 AdjustAttachedLine ();
829 else
830 AdjustTwoLine (PCB->Clipping - 1);
831 break;
832 /* point insertion mode */
833 case INSERTPOINT_MODE:
834 pnt = AdjustInsertPoint ();
835 if (pnt)
836 InsertedPoint = *pnt;
837 break;
838 case ROTATE_MODE:
839 break;
843 /* ---------------------------------------------------------------------------
844 * creates points of a line
846 static void
847 NotifyLine (void)
849 int type = NO_TYPE;
850 void *ptr1, *ptr2, *ptr3;
852 if (!Marked.status || TEST_FLAG (LOCALREFFLAG, PCB))
853 SetLocalRef (Crosshair.X, Crosshair.Y, True);
854 switch (Crosshair.AttachedLine.State)
856 case STATE_FIRST: /* first point */
857 if (PCB->RatDraw && SearchScreen (Crosshair.X, Crosshair.Y,
858 PAD_TYPE | PIN_TYPE, &ptr1, &ptr1,
859 &ptr1) == NO_TYPE)
861 gui->beep ();
862 break;
864 if (TEST_FLAG (AUTODRCFLAG, PCB) && Settings.Mode == LINE_MODE)
866 type = SearchScreen (Crosshair.X, Crosshair.Y,
867 PIN_TYPE | PAD_TYPE | VIA_TYPE, &ptr1, &ptr2,
868 &ptr3);
869 LookupConnection (Crosshair.X, Crosshair.Y, True, TO_PCB (1),
870 FOUNDFLAG);
872 if (type == PIN_TYPE || type == VIA_TYPE)
874 Crosshair.AttachedLine.Point1.X =
875 Crosshair.AttachedLine.Point2.X = ((PinTypePtr) ptr2)->X;
876 Crosshair.AttachedLine.Point1.Y =
877 Crosshair.AttachedLine.Point2.Y = ((PinTypePtr) ptr2)->Y;
879 else if (type == PAD_TYPE)
881 PadTypePtr pad = (PadTypePtr) ptr2;
882 float d1, d2;
883 d1 = SQUARE (Crosshair.X - pad->Point1.X) +
884 SQUARE (Crosshair.Y - pad->Point1.Y);
885 d2 = SQUARE (Crosshair.X - pad->Point2.X) +
886 SQUARE (Crosshair.Y - pad->Point2.Y);
887 if (d2 < d1)
889 Crosshair.AttachedLine.Point1 =
890 Crosshair.AttachedLine.Point2 = pad->Point2;
892 else
894 Crosshair.AttachedLine.Point1 =
895 Crosshair.AttachedLine.Point2 = pad->Point1;
898 else
900 Crosshair.AttachedLine.Point1.X =
901 Crosshair.AttachedLine.Point2.X = Crosshair.X;
902 Crosshair.AttachedLine.Point1.Y =
903 Crosshair.AttachedLine.Point2.Y = Crosshair.Y;
905 Crosshair.AttachedLine.State = STATE_SECOND;
906 break;
908 case STATE_SECOND:
909 /* fall through to third state too */
910 lastLayer = CURRENT;
911 default: /* all following points */
912 Crosshair.AttachedLine.State = STATE_THIRD;
913 break;
917 /* ---------------------------------------------------------------------------
918 * create first or second corner of a marked block
920 static void
921 NotifyBlock (void)
923 HideCrosshair (True);
924 switch (Crosshair.AttachedBox.State)
926 case STATE_FIRST: /* setup first point */
927 Crosshair.AttachedBox.Point1.X =
928 Crosshair.AttachedBox.Point2.X = Crosshair.X;
929 Crosshair.AttachedBox.Point1.Y =
930 Crosshair.AttachedBox.Point2.Y = Crosshair.Y;
931 Crosshair.AttachedBox.State = STATE_SECOND;
932 break;
934 case STATE_SECOND: /* setup second point */
935 Crosshair.AttachedBox.State = STATE_THIRD;
936 break;
938 RestoreCrosshair (True);
942 /* ---------------------------------------------------------------------------
944 * does what's appropriate for the current mode setting. This normally
945 * means creation of an object at the current crosshair location.
947 * new created objects are added to the create undo list of course
949 static void
950 NotifyMode (void)
952 void *ptr1, *ptr2, *ptr3;
953 int type;
955 if (Settings.RatWarn)
956 ClearWarnings ();
957 switch (Settings.Mode)
959 case ARROW_MODE:
961 int test;
962 hidval hv;
964 Note.Click = True;
965 /* do something after click time */
966 gui->add_timer (click_cb, CLICK_TIME, hv);
968 /* see if we clicked on something already selected
969 * (Note.Moving) or clicked on a MOVE_TYPE
970 * (Note.Hit)
972 for (test = (SELECT_TYPES | MOVE_TYPES) & ~RATLINE_TYPE;
973 test; test &= ~type)
975 type = SearchScreen (Note.X, Note.Y, test, &ptr1, &ptr2, &ptr3);
976 if (!Note.Hit && (type & MOVE_TYPES) &&
977 !TEST_FLAG (LOCKFLAG, (PinTypePtr) ptr2))
979 Note.Hit = type;
980 Note.ptr1 = ptr1;
981 Note.ptr2 = ptr2;
982 Note.ptr3 = ptr3;
984 if (!Note.Moving && (type & SELECT_TYPES) &&
985 TEST_FLAG (SELECTEDFLAG, (PinTypePtr) ptr2))
986 Note.Moving = True;
987 if ((Note.Hit && Note.Moving) || type == NO_TYPE)
988 break;
990 break;
993 case VIA_MODE:
995 PinTypePtr via;
997 if (!PCB->ViaOn)
999 Message (_("You must turn via visibility on before\n"
1000 "you can place vias\n"));
1001 break;
1003 if ((via = CreateNewVia (PCB->Data, Note.X, Note.Y,
1004 Settings.ViaThickness, 2 * Settings.Keepaway,
1005 0, Settings.ViaDrillingHole, NULL,
1006 NoFlags ())) != NULL)
1008 AddObjectToCreateUndoList (VIA_TYPE, via, via, via);
1009 IncrementUndoSerialNumber ();
1010 DrawVia (via, 0);
1011 Draw ();
1013 break;
1016 case ARC_MODE:
1018 switch (Crosshair.AttachedBox.State)
1020 case STATE_FIRST:
1021 Crosshair.AttachedBox.Point1.X =
1022 Crosshair.AttachedBox.Point2.X = Note.X;
1023 Crosshair.AttachedBox.Point1.Y =
1024 Crosshair.AttachedBox.Point2.Y = Note.Y;
1025 Crosshair.AttachedBox.State = STATE_SECOND;
1026 break;
1028 case STATE_SECOND:
1029 case STATE_THIRD:
1031 ArcTypePtr arc;
1032 LocationType wx, wy;
1033 int sa, dir;
1035 wx = Note.X - Crosshair.AttachedBox.Point1.X;
1036 wy = Note.Y - Crosshair.AttachedBox.Point1.Y;
1037 if (XOR (Crosshair.AttachedBox.otherway, abs (wy) > abs (wx)))
1039 Crosshair.AttachedBox.Point2.X =
1040 Crosshair.AttachedBox.Point1.X + abs (wy) * SGNZ (wx);
1041 sa = (wx >= 0) ? 0 : 180;
1042 #ifdef ARC45
1043 if (abs (wy) / 2 >= abs (wx))
1044 dir = (SGNZ (wx) == SGNZ (wy)) ? 45 : -45;
1045 else
1046 #endif
1047 dir = (SGNZ (wx) == SGNZ (wy)) ? 90 : -90;
1049 else
1051 Crosshair.AttachedBox.Point2.Y =
1052 Crosshair.AttachedBox.Point1.Y + abs (wx) * SGNZ (wy);
1053 sa = (wy >= 0) ? -90 : 90;
1054 #ifdef ARC45
1055 if (abs (wx) / 2 >= abs (wy))
1056 dir = (SGNZ (wx) == SGNZ (wy)) ? -45 : 45;
1057 else
1058 #endif
1059 dir = (SGNZ (wx) == SGNZ (wy)) ? -90 : 90;
1060 wy = wx;
1062 if (abs (wy) > 0 && (arc = CreateNewArcOnLayer (CURRENT,
1063 Crosshair.
1064 AttachedBox.
1065 Point2.X,
1066 Crosshair.
1067 AttachedBox.
1068 Point2.Y,
1069 abs (wy), sa,
1070 dir,
1071 Settings.
1072 LineThickness,
1073 2 * Settings.
1074 Keepaway,
1075 MakeFlags
1076 (TEST_FLAG
1077 (CLEARNEWFLAG,
1078 PCB) ?
1079 CLEARLINEFLAG :
1080 0))))
1082 BoxTypePtr bx;
1084 bx = GetArcEnds (arc);
1085 Crosshair.AttachedBox.Point1.X =
1086 Crosshair.AttachedBox.Point2.X = bx->X2;
1087 Crosshair.AttachedBox.Point1.Y =
1088 Crosshair.AttachedBox.Point2.Y = bx->Y2;
1089 AddObjectToCreateUndoList (ARC_TYPE, CURRENT, arc, arc);
1090 IncrementUndoSerialNumber ();
1091 addedLines++;
1092 DrawArc (CURRENT, arc, 0);
1093 Draw ();
1094 Crosshair.AttachedBox.State = STATE_THIRD;
1096 break;
1099 break;
1101 case LOCK_MODE:
1103 type = SearchScreen (Note.X, Note.Y, LOCK_TYPES, &ptr1, &ptr2, &ptr3);
1104 if (type == ELEMENT_TYPE)
1106 ElementTypePtr element = (ElementTypePtr) ptr2;
1108 TOGGLE_FLAG (LOCKFLAG, element);
1109 PIN_LOOP (element);
1111 TOGGLE_FLAG (LOCKFLAG, pin);
1112 CLEAR_FLAG (SELECTEDFLAG, pin);
1114 END_LOOP;
1115 PAD_LOOP (element);
1117 TOGGLE_FLAG (LOCKFLAG, pad);
1118 CLEAR_FLAG (SELECTEDFLAG, pad);
1120 END_LOOP;
1121 CLEAR_FLAG (SELECTEDFLAG, element);
1122 /* always re-draw it since I'm too lazy
1123 * to tell if a selected flag changed
1125 DrawElement (element, 0);
1126 Draw ();
1127 hid_actionl ("Report", "Object", NULL);
1129 else if (type != NO_TYPE)
1131 TextTypePtr thing = (TextTypePtr) ptr3;
1132 TOGGLE_FLAG (LOCKFLAG, thing);
1133 if (TEST_FLAG (LOCKFLAG, thing)
1134 && TEST_FLAG (SELECTEDFLAG, thing))
1136 /* this is not un-doable since LOCK isn't */
1137 CLEAR_FLAG (SELECTEDFLAG, thing);
1138 DrawObject (type, ptr1, ptr2, 0);
1139 Draw ();
1141 hid_actionl ("Report", "Object", NULL);
1143 break;
1145 case THERMAL_MODE:
1147 if (((type
1149 SearchScreen (Note.X, Note.Y, PIN_TYPES, &ptr1, &ptr2,
1150 &ptr3)) != NO_TYPE)
1151 && !TEST_FLAG (HOLEFLAG, (PinTypePtr) ptr3))
1153 if (gui->shift_is_pressed ())
1155 int tstyle = GET_THERM (INDEXOFCURRENT, (PinTypePtr) ptr3);
1156 tstyle++;
1157 if (tstyle > 5)
1158 tstyle = 1;
1159 ChangeObjectThermal (type, ptr1, ptr2, ptr3, tstyle);
1161 else if (GET_THERM (INDEXOFCURRENT, (PinTypePtr) ptr3))
1162 ChangeObjectThermal (type, ptr1, ptr2, ptr3, 0);
1163 else
1164 ChangeObjectThermal (type, ptr1, ptr2, ptr3, PCB->ThermStyle);
1166 break;
1169 case LINE_MODE:
1170 /* do update of position */
1171 NotifyLine ();
1172 if (Crosshair.AttachedLine.State != STATE_THIRD)
1173 break;
1175 /* Remove anchor if clicking on start point;
1176 * this means we can't paint 0 length lines
1177 * which could be used for square SMD pads.
1178 * Instead use a very small delta, or change
1179 * the file after saving.
1181 if (Crosshair.X == Crosshair.AttachedLine.Point1.X
1182 && Crosshair.Y == Crosshair.AttachedLine.Point1.Y)
1184 SetMode (LINE_MODE);
1185 break;
1188 if (PCB->RatDraw)
1190 RatTypePtr line;
1191 if ((line = AddNet ()))
1193 addedLines++;
1194 AddObjectToCreateUndoList (RATLINE_TYPE, line, line, line);
1195 IncrementUndoSerialNumber ();
1196 DrawRat (line, 0);
1197 Crosshair.AttachedLine.Point1.X =
1198 Crosshair.AttachedLine.Point2.X;
1199 Crosshair.AttachedLine.Point1.Y =
1200 Crosshair.AttachedLine.Point2.Y;
1201 Draw ();
1203 break;
1205 else
1206 /* create line if both ends are determined && length != 0 */
1208 LineTypePtr line;
1210 if (PCB->Clipping
1211 && Crosshair.AttachedLine.Point1.X ==
1212 Crosshair.AttachedLine.Point2.X
1213 && Crosshair.AttachedLine.Point1.Y ==
1214 Crosshair.AttachedLine.Point2.Y
1215 && (Crosshair.AttachedLine.Point2.X != Note.X
1216 || Crosshair.AttachedLine.Point2.Y != Note.Y))
1218 /* We will paint only the second line segment.
1219 Since we only check for vias on the first segment,
1220 swap them so we only paint the first segment. */
1221 Crosshair.AttachedLine.Point2.X = Note.X;
1222 Crosshair.AttachedLine.Point2.Y = Note.Y;
1225 if ((Crosshair.AttachedLine.Point1.X !=
1226 Crosshair.AttachedLine.Point2.X
1227 || Crosshair.AttachedLine.Point1.Y !=
1228 Crosshair.AttachedLine.Point2.Y)
1229 && (line =
1230 CreateDrawnLineOnLayer (CURRENT,
1231 Crosshair.AttachedLine.Point1.X,
1232 Crosshair.AttachedLine.Point1.Y,
1233 Crosshair.AttachedLine.Point2.X,
1234 Crosshair.AttachedLine.Point2.Y,
1235 Settings.LineThickness,
1236 2 * Settings.Keepaway,
1237 MakeFlags ((TEST_FLAG
1238 (AUTODRCFLAG,
1239 PCB) ? FOUNDFLAG : 0) |
1240 (TEST_FLAG
1241 (CLEARNEWFLAG,
1242 PCB) ? CLEARLINEFLAG :
1243 0)))) != NULL)
1245 PinTypePtr via;
1247 addedLines++;
1248 AddObjectToCreateUndoList (LINE_TYPE, CURRENT, line, line);
1249 DrawLine (CURRENT, line, 0);
1250 /* place a via if vias are visible, the layer is
1251 in a new group since the last line and there
1252 isn't a pin already here */
1253 if (PCB->ViaOn && GetLayerGroupNumberByPointer (CURRENT) !=
1254 GetLayerGroupNumberByPointer (lastLayer) &&
1255 SearchObjectByLocation (PIN_TYPES, &ptr1, &ptr2, &ptr3,
1256 Crosshair.AttachedLine.Point1.X,
1257 Crosshair.AttachedLine.Point1.Y,
1258 Settings.ViaThickness / 2) ==
1259 NO_TYPE
1260 && (via =
1261 CreateNewVia (PCB->Data,
1262 Crosshair.AttachedLine.Point1.X,
1263 Crosshair.AttachedLine.Point1.Y,
1264 Settings.ViaThickness,
1265 2 * Settings.Keepaway, 0,
1266 Settings.ViaDrillingHole, NULL,
1267 NoFlags ())) != NULL)
1269 AddObjectToCreateUndoList (VIA_TYPE, via, via, via);
1270 DrawVia (via, 0);
1272 /* copy the coordinates */
1273 Crosshair.AttachedLine.Point1.X =
1274 Crosshair.AttachedLine.Point2.X;
1275 Crosshair.AttachedLine.Point1.Y =
1276 Crosshair.AttachedLine.Point2.Y;
1277 IncrementUndoSerialNumber ();
1278 lastLayer = CURRENT;
1280 if (PCB->Clipping && (Note.X != Crosshair.AttachedLine.Point2.X
1281 || Note.Y !=
1282 Crosshair.AttachedLine.Point2.Y)
1283 && (line =
1284 CreateDrawnLineOnLayer (CURRENT,
1285 Crosshair.AttachedLine.Point2.X,
1286 Crosshair.AttachedLine.Point2.Y,
1287 Note.X, Note.Y,
1288 Settings.LineThickness,
1289 2 * Settings.Keepaway,
1290 MakeFlags ((TEST_FLAG
1291 (AUTODRCFLAG,
1292 PCB) ? FOUNDFLAG : 0) |
1293 (TEST_FLAG
1294 (CLEARNEWFLAG,
1295 PCB) ? CLEARLINEFLAG :
1296 0)))) != NULL)
1298 addedLines++;
1299 AddObjectToCreateUndoList (LINE_TYPE, CURRENT, line, line);
1300 IncrementUndoSerialNumber ();
1301 DrawLine (CURRENT, line, 0);
1302 /* move to new start point */
1303 Crosshair.AttachedLine.Point1.X = Note.X;
1304 Crosshair.AttachedLine.Point1.Y = Note.Y;
1305 Crosshair.AttachedLine.Point2.X = Note.X;
1306 Crosshair.AttachedLine.Point2.Y = Note.Y;
1307 if (TEST_FLAG (SWAPSTARTDIRFLAG, PCB))
1309 PCB->Clipping ^= 3;
1312 Draw ();
1314 break;
1316 case RECTANGLE_MODE:
1317 /* do update of position */
1318 NotifyBlock ();
1320 /* create rectangle if both corners are determined
1321 * and width, height are != 0
1323 if (Crosshair.AttachedBox.State == STATE_THIRD &&
1324 Crosshair.AttachedBox.Point1.X != Crosshair.AttachedBox.Point2.X &&
1325 Crosshair.AttachedBox.Point1.Y != Crosshair.AttachedBox.Point2.Y)
1327 PolygonTypePtr polygon;
1329 if ((polygon = CreateNewPolygonFromRectangle (CURRENT,
1330 Crosshair.
1331 AttachedBox.Point1.X,
1332 Crosshair.
1333 AttachedBox.Point1.Y,
1334 Crosshair.
1335 AttachedBox.Point2.X,
1336 Crosshair.
1337 AttachedBox.Point2.Y,
1338 MakeFlags
1339 (CLEARPOLYFLAG))) !=
1340 NULL)
1342 AddObjectToCreateUndoList (POLYGON_TYPE, CURRENT,
1343 polygon, polygon);
1344 IncrementUndoSerialNumber ();
1345 DrawPolygon (CURRENT, polygon, 0);
1346 Draw ();
1349 /* reset state to 'first corner' */
1350 Crosshair.AttachedBox.State = STATE_FIRST;
1352 break;
1354 case TEXT_MODE:
1356 char *string;
1358 if ((string = gui->prompt_for (_("Enter text:"), "")) != NULL)
1360 TextTypePtr text;
1361 int flag = NOFLAG;
1363 if (GetLayerGroupNumberByNumber (INDEXOFCURRENT) ==
1364 GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER))
1365 flag = ONSOLDERFLAG;
1366 if ((text = CreateNewText (CURRENT, &PCB->Font, Note.X,
1367 Note.Y, 0, Settings.TextScale,
1368 string, MakeFlags (flag))) != NULL)
1370 AddObjectToCreateUndoList (TEXT_TYPE, CURRENT, text, text);
1371 IncrementUndoSerialNumber ();
1372 DrawText (CURRENT, text, 0);
1373 Draw ();
1376 /* free memory allocated by gui->prompt_for() */
1377 free (string);
1379 break;
1382 case POLYGON_MODE:
1384 PointTypePtr points = Crosshair.AttachedPolygon.Points;
1385 Cardinal n = Crosshair.AttachedPolygon.PointN;
1387 /* do update of position; use the 'LINE_MODE' mechanism */
1388 NotifyLine ();
1390 /* check if this is the last point of a polygon */
1391 if (n >= 3 &&
1392 points->X == Crosshair.AttachedLine.Point2.X &&
1393 points->Y == Crosshair.AttachedLine.Point2.Y)
1395 CopyAttachedPolygonToLayer ();
1396 Draw ();
1397 break;
1400 /* create new point if it's the first one or if it's
1401 * different to the last one
1403 if (!n ||
1404 points[n - 1].X != Crosshair.AttachedLine.Point2.X ||
1405 points[n - 1].Y != Crosshair.AttachedLine.Point2.Y)
1407 CreateNewPointInPolygon (&Crosshair.AttachedPolygon,
1408 Crosshair.AttachedLine.Point2.X,
1409 Crosshair.AttachedLine.Point2.Y);
1411 /* copy the coordinates */
1412 Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X;
1413 Crosshair.AttachedLine.Point1.Y = Crosshair.AttachedLine.Point2.Y;
1415 break;
1418 case PASTEBUFFER_MODE:
1420 TextType estr[MAX_ELEMENTNAMES];
1421 ElementTypePtr e = 0;
1423 if (gui->shift_is_pressed ())
1425 int type =
1426 SearchScreen (Note.X, Note.Y, ELEMENT_TYPE, &ptr1, &ptr2,
1427 &ptr3);
1428 if (type == ELEMENT_TYPE)
1430 e = (ElementTypePtr) ptr1;
1431 if (e)
1433 memcpy (estr, e->Name,
1434 MAX_ELEMENTNAMES * sizeof (TextType));
1435 memset (e->Name, 0, MAX_ELEMENTNAMES * sizeof (TextType));
1436 RemoveElement (e);
1440 if (CopyPastebufferToLayout (Note.X, Note.Y))
1441 SetChangedFlag (True);
1442 if (e)
1444 int type =
1445 SearchScreen (Note.X, Note.Y, ELEMENT_TYPE, &ptr1, &ptr2,
1446 &ptr3);
1447 if (type == ELEMENT_TYPE && ptr1)
1449 int i, save_n;
1450 e = (ElementTypePtr) ptr1;
1452 save_n = NAME_INDEX (PCB);
1454 for (i = 0; i < MAX_ELEMENTNAMES; i++)
1456 if (i == save_n)
1457 EraseElementName (e);
1458 r_delete_entry (PCB->Data->name_tree[i],
1459 (BoxType *) & (e->Name[i]));
1460 memcpy (&(e->Name[i]), &(estr[i]), sizeof (TextType));
1461 e->Name[i].Element = e;
1462 SetTextBoundingBox (&PCB->Font, &(e->Name[i]));
1463 r_insert_entry (PCB->Data->name_tree[i],
1464 (BoxType *) & (e->Name[i]), 0);
1465 if (i == save_n)
1466 DrawElementName (e, 0);
1470 break;
1473 case REMOVE_MODE:
1474 if ((type =
1475 SearchScreen (Note.X, Note.Y, REMOVE_TYPES, &ptr1, &ptr2,
1476 &ptr3)) != NO_TYPE)
1478 if (TEST_FLAG (LOCKFLAG, (LineTypePtr) ptr2))
1480 Message (_("Sorry, the object is locked\n"));
1481 break;
1483 if (type == ELEMENT_TYPE)
1485 RubberbandTypePtr ptr;
1486 int i;
1488 Crosshair.AttachedObject.RubberbandN = 0;
1489 LookupRatLines (type, ptr1, ptr2, ptr3);
1490 ptr = Crosshair.AttachedObject.Rubberband;
1491 for (i = 0; i < Crosshair.AttachedObject.RubberbandN; i++)
1493 if (PCB->RatOn)
1494 EraseRat ((RatTypePtr) ptr->Line);
1495 MoveObjectToRemoveUndoList (RATLINE_TYPE,
1496 ptr->Line, ptr->Line,
1497 ptr->Line);
1498 ptr++;
1501 RemoveObject (type, ptr1, ptr2, ptr3);
1502 IncrementUndoSerialNumber ();
1503 SetChangedFlag (True);
1505 break;
1507 case ROTATE_MODE:
1508 RotateScreenObject (Note.X, Note.Y,
1509 gui->shift_is_pressed ()? (SWAP_IDENT ?
1510 1 : 3)
1511 : (SWAP_IDENT ? 3 : 1));
1512 break;
1514 /* both are almost the same */
1515 case COPY_MODE:
1516 case MOVE_MODE:
1517 switch (Crosshair.AttachedObject.State)
1519 /* first notify, lookup object */
1520 case STATE_FIRST:
1522 int types = (Settings.Mode == COPY_MODE) ?
1523 COPY_TYPES : MOVE_TYPES;
1525 Crosshair.AttachedObject.Type =
1526 SearchScreen (Note.X, Note.Y, types,
1527 &Crosshair.AttachedObject.Ptr1,
1528 &Crosshair.AttachedObject.Ptr2,
1529 &Crosshair.AttachedObject.Ptr3);
1530 if (Crosshair.AttachedObject.Type != NO_TYPE)
1532 if (Settings.Mode == MOVE_MODE &&
1533 TEST_FLAG (LOCKFLAG, (PinTypePtr)
1534 Crosshair.AttachedObject.Ptr2))
1536 Message (_("Sorry, the object is locked\n"));
1537 Crosshair.AttachedObject.Type = NO_TYPE;
1539 else
1540 AttachForCopy (Note.X, Note.Y);
1542 break;
1545 /* second notify, move or copy object */
1546 case STATE_SECOND:
1547 if (Settings.Mode == COPY_MODE)
1548 CopyObject (Crosshair.AttachedObject.Type,
1549 Crosshair.AttachedObject.Ptr1,
1550 Crosshair.AttachedObject.Ptr2,
1551 Crosshair.AttachedObject.Ptr3,
1552 Note.X - Crosshair.AttachedObject.X,
1553 Note.Y - Crosshair.AttachedObject.Y);
1554 else
1556 MoveObjectAndRubberband (Crosshair.AttachedObject.Type,
1557 Crosshair.AttachedObject.Ptr1,
1558 Crosshair.AttachedObject.Ptr2,
1559 Crosshair.AttachedObject.Ptr3,
1560 Note.X - Crosshair.AttachedObject.X,
1561 Note.Y - Crosshair.AttachedObject.Y);
1562 SetLocalRef (0, 0, False);
1564 SetChangedFlag (True);
1566 /* reset identifiers */
1567 Crosshair.AttachedObject.Type = NO_TYPE;
1568 Crosshair.AttachedObject.State = STATE_FIRST;
1569 break;
1571 break;
1573 /* insert a point into a polygon/line/... */
1574 case INSERTPOINT_MODE:
1575 switch (Crosshair.AttachedObject.State)
1577 /* first notify, lookup object */
1578 case STATE_FIRST:
1579 Crosshair.AttachedObject.Type =
1580 SearchScreen (Note.X, Note.Y, INSERT_TYPES,
1581 &Crosshair.AttachedObject.Ptr1,
1582 &Crosshair.AttachedObject.Ptr2,
1583 &Crosshair.AttachedObject.Ptr3);
1585 if (Crosshair.AttachedObject.Type != NO_TYPE)
1587 if (TEST_FLAG (LOCKFLAG, (PolygonTypePtr)
1588 Crosshair.AttachedObject.Ptr2))
1590 Message (_("Sorry, the object is locked\n"));
1591 Crosshair.AttachedObject.Type = NO_TYPE;
1592 break;
1594 else
1596 /* get starting point of nearest segment */
1597 if (Crosshair.AttachedObject.Type == POLYGON_TYPE)
1599 fake.poly =
1600 (PolygonTypePtr) Crosshair.AttachedObject.Ptr2;
1601 polyIndex =
1602 GetLowestDistancePolygonPoint (fake.poly, Note.X,
1603 Note.Y);
1604 fake.line.Point1 = fake.poly->Points[polyIndex];
1605 fake.line.Point2 = (polyIndex) ?
1606 fake.poly->Points[polyIndex - 1]
1607 : fake.poly->Points[fake.poly->PointN - 1];
1608 Crosshair.AttachedObject.Ptr2 = &fake.line;
1611 Crosshair.AttachedObject.State = STATE_SECOND;
1612 InsertedPoint = *AdjustInsertPoint ();
1615 break;
1617 /* second notify, insert new point into object */
1618 case STATE_SECOND:
1619 if (Crosshair.AttachedObject.Type == POLYGON_TYPE)
1620 InsertPointIntoObject (POLYGON_TYPE,
1621 Crosshair.AttachedObject.Ptr1, fake.poly,
1622 &polyIndex,
1623 InsertedPoint.X, InsertedPoint.Y, False);
1624 else
1625 InsertPointIntoObject (Crosshair.AttachedObject.Type,
1626 Crosshair.AttachedObject.Ptr1,
1627 Crosshair.AttachedObject.Ptr2,
1628 &polyIndex,
1629 InsertedPoint.X, InsertedPoint.Y, False);
1630 SetChangedFlag (True);
1632 /* reset identifiers */
1633 Crosshair.AttachedObject.Type = NO_TYPE;
1634 Crosshair.AttachedObject.State = STATE_FIRST;
1635 break;
1637 break;
1642 /* --------------------------------------------------------------------------- */
1644 static const char atomic_syntax[] = "Atomic(Save|Restore|Close|Block)";
1646 static const char atomic_help[] = "Save or restore the undo serial number.";
1648 /* %start-doc actions Atomic
1650 This action allows making multiple-action bindings into an atomic
1651 operation that will be undone by a single Undo command. For example,
1652 to optimize rat lines, you'd delete the rats and re-add them. To
1653 group these into a single undo, you'd want the deletions and the
1654 additions to have the same undo serial number. So, you @code{Save},
1655 delete the rats, @code{Restore}, add the rats - using the same serial
1656 number as the deletes, then @code{Block}, which checks to see if the
1657 deletions or additions actually did anything. If not, the serial
1658 number is set to the saved number, as there's nothing to undo. If
1659 something did happen, the serial number is incremented so that these
1660 actions are counted as a single undo step.
1662 @table @code
1664 @item Save
1665 Saves the undo serial number.
1667 @item Restore
1668 Returns it to the last saved number.
1670 @item Close
1671 Sets it to 1 greater than the last save.
1673 @item Block
1674 Does a Restore if there was nothing to undo, else does a Close.
1676 @end table
1678 %end-doc */
1680 static int
1681 ActionAtomic (int argc, char **argv, int x, int y)
1683 if (argc != 1)
1684 AFAIL (atomic);
1686 switch (GetFunctionID (argv[0]))
1688 case F_Save:
1689 SaveUndoSerialNumber ();
1690 break;
1691 case F_Restore:
1692 RestoreUndoSerialNumber ();
1693 break;
1694 case F_Close:
1695 RestoreUndoSerialNumber ();
1696 IncrementUndoSerialNumber ();
1697 break;
1698 case F_Block:
1699 RestoreUndoSerialNumber ();
1700 if (Bumped)
1701 IncrementUndoSerialNumber ();
1702 break;
1704 return 0;
1707 /* -------------------------------------------------------------------------- */
1709 static const char drc_syntax[] = "DRC()";
1711 static const char drc_help[] = "Invoke the DRC check.";
1713 /* %start-doc actions DRC
1715 Note that the design rule check uses the current board rule settings,
1716 not the current style settings.
1718 %end-doc */
1720 static int
1721 ActionDRCheck (int argc, char **argv, int x, int y)
1723 Cardinal count;
1725 Message (_("Rules are minspace %d.%02d, minoverlap %d.%d "
1726 "minwidth %d.%02d, minsilk %d.%02d\n"
1727 "min drill %d.%02d, min annular ring %d.%02d\n"),
1728 (PCB->Bloat + 1) / 100, (PCB->Bloat + 1) % 100,
1729 PCB->Shrink / 100, PCB->Shrink % 100,
1730 PCB->minWid / 100, PCB->minWid % 100,
1731 PCB->minSlk / 100, PCB->minSlk % 100,
1732 PCB->minDrill / 100, PCB->minDrill % 100,
1733 PCB->minRing / 100, PCB->minRing % 100);
1734 HideCrosshair (True);
1735 count = DRCAll ();
1736 if (count == 0)
1737 Message (_("No DRC problems found.\n"));
1738 else
1739 Message (_("Found %d design rule errors\n"), count);
1740 RestoreCrosshair (True);
1741 return 0;
1744 /* -------------------------------------------------------------------------- */
1746 static const char dumplibrary_syntax[] = "DumpLibrary()";
1748 static const char dumplibrary_help[] =
1749 "Display the entire contents of the libraries.";
1751 /* %start-doc actions DumpLibrary
1754 %end-doc */
1756 static int
1757 ActionDumpLibrary (int argc, char **argv, int x, int y)
1759 int i, j;
1761 printf ("**** Do not count on this format. It will change ****\n\n");
1762 printf ("MenuN = %d\n", Library.MenuN);
1763 printf ("MenuMax = %d\n", Library.MenuMax);
1764 for (i = 0; i < Library.MenuN; i++)
1766 printf ("Library #%d:\n", i);
1767 printf (" EntryN = %d\n", Library.Menu[i].EntryN);
1768 printf (" EntryMax = %d\n", Library.Menu[i].EntryMax);
1769 printf (" Name = \"%s\"\n", UNKNOWN (Library.Menu[i].Name));
1770 printf (" directory = \"%s\"\n",
1771 UNKNOWN (Library.Menu[i].directory));
1772 printf (" Style = \"%s\"\n", UNKNOWN (Library.Menu[i].Style));
1773 printf (" flag = %d\n", Library.Menu[i].flag);
1775 for (j = 0; j < Library.Menu[i].EntryN; j++)
1777 printf (" #%4d: ", j);
1778 if (Library.Menu[i].Entry[j].Template == (char *) -1)
1780 printf ("newlib: \"%s\"\n",
1781 UNKNOWN (Library.Menu[i].Entry[j].ListEntry));
1783 else
1785 printf ("\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"\n",
1786 UNKNOWN (Library.Menu[i].Entry[j].ListEntry),
1787 UNKNOWN (Library.Menu[i].Entry[j].Template),
1788 UNKNOWN (Library.Menu[i].Entry[j].Package),
1789 UNKNOWN (Library.Menu[i].Entry[j].Value),
1790 UNKNOWN (Library.Menu[i].Entry[j].Description));
1795 return 0;
1798 /* -------------------------------------------------------------------------- */
1800 static const char flip_syntax[] = "Flip(Object|Selected|SelectedElements)";
1802 static const char flip_help[] =
1803 "Flip an element to the opposite side of the board.";
1805 /* %start-doc actions Flip
1807 Note that the location of the element will be symmetric about the
1808 cursor location; i.e. if the part you are pointing at will still be at
1809 the same spot once the element is on the other side. When flipping
1810 multiple elements, this retains their positions relative to each
1811 other, not their absolute positions on the board.
1813 %end-doc */
1815 static int
1816 ActionFlip (int argc, char **argv, int x, int y)
1818 char *function = ARG (0);
1819 ElementTypePtr element;
1820 void *ptrtmp;
1821 int err = 0;
1823 if (function)
1825 HideCrosshair (True);
1826 switch (GetFunctionID (function))
1828 case F_Object:
1829 if ((SearchScreen (x, y, ELEMENT_TYPE,
1830 &ptrtmp, &ptrtmp, &ptrtmp)) != NO_TYPE)
1832 element = (ElementTypePtr) ptrtmp;
1833 ChangeElementSide (element, 2 * Crosshair.Y - PCB->MaxHeight);
1834 IncrementUndoSerialNumber ();
1835 Draw ();
1837 break;
1838 case F_Selected:
1839 case F_SelectedElements:
1840 ChangeSelectedElementSide ();
1841 break;
1842 default:
1843 err = 1;
1844 break;
1846 RestoreCrosshair (True);
1847 if (!err)
1848 return 0;
1851 AFAIL (flip);
1854 /* -------------------------------------------------------------------------- */
1856 static const char message_syntax[] = "Message(message)";
1858 static const char message_help[] = "Writes a message to the log window.";
1860 /* %start-doc actions Message
1862 This action displays a message to the log window. This action is primarily
1863 provided for use by other programs which may interface with PCB. If
1864 multiple arguments are given, each one is sent to the log window
1865 followed by a newline.
1867 %end-doc */
1869 static int
1870 ActionMessage (int argc, char **argv, int x, int y)
1872 int i;
1874 if (argc < 1)
1875 AFAIL (message);
1877 for (i = 0; i < argc; i++)
1879 Message (argv[i]);
1880 Message ("\n");
1883 return 0;
1887 /* -------------------------------------------------------------------------- */
1889 static const char setthermal_syntax[] =
1890 "SetThermal(Object|SelectedPins|SelectedVias|Selected, Style)";
1892 static const char setthermal_help[] =
1893 "Set the thermal (on the current layer) of pins or vias to the given style.\n"
1894 "Style = 0 means no thermal.\n"
1895 "Style = 1 has diagonal fingers with sharp edges.\n"
1896 "Style = 2 has horizontal and vertical fingers with sharp edges.\n"
1897 "Style = 3 is a solid connection to the plane."
1898 "Style = 4 has diagonal fingers with rounded edges.\n"
1899 "Style = 5 has horizontal and vertical fingers with rounded edges.\n";
1901 /* %start-doc actions SetThermal
1903 This changes how/whether pins or vias connect to any rectangle or polygon
1904 on the current layer. The first argument can specify one object, or all
1905 selected pins, or all selected vias, or all selected pins and vias.
1906 The second argument specifies the style of connection.
1907 There are 5 possibilities:
1908 0 - no connection,
1909 1 - 45 degree fingers with sharp edges,
1910 2 - horizontal & vertical fingers with sharp edges,
1911 3 - solid connection,
1912 4 - 45 degree fingers with rounded corners,
1913 5 - horizontal & vertical fingers with rounded corners.
1915 Pins and Vias may have thermals whether or not there is a polygon available
1916 to connect with. However, they will have no effect without the polygon.
1917 %end-doc */
1919 static int
1920 ActionSetThermal (int argc, char **argv, int x, int y)
1922 char *function = ARG (0);
1923 char *style = ARG (1);
1924 void *ptr1, *ptr2, *ptr3;
1925 int type, kind;
1926 int err = 0;
1928 if (function && *function && style && *style)
1930 Boolean absolute;
1932 kind = GetValue (style, NULL, &absolute);
1933 HideCrosshair (True);
1934 if (absolute)
1935 switch (GetFunctionID (function))
1937 case F_Object:
1938 if ((type =
1939 SearchScreen (Crosshair.X, Crosshair.Y, CHANGETHERMAL_TYPES,
1940 &ptr1, &ptr2, &ptr3)) != NO_TYPE)
1942 ChangeObjectThermal (type, ptr1, ptr2, ptr3, kind);
1943 IncrementUndoSerialNumber ();
1944 Draw ();
1946 break;
1947 case F_SelectedPins:
1948 ChangeSelectedThermals (PIN_TYPE, kind);
1949 break;
1950 case F_SelectedVias:
1951 ChangeSelectedThermals (VIA_TYPE, kind);
1952 break;
1953 case F_Selected:
1954 case F_SelectedElements:
1955 ChangeSelectedThermals (CHANGETHERMAL_TYPES, kind);
1956 break;
1957 default:
1958 err = 1;
1959 break;
1961 else
1962 err = 1;
1963 RestoreCrosshair (True);
1964 if (!err)
1965 return 0;
1968 AFAIL (setthermal);
1971 /* ---------------------------------------------------------------------------
1972 * action routine to move the X pointer relative to the current position
1973 * syntax: MovePointer(deltax,deltay)
1975 void
1976 ActionMovePointer (char *deltax, char *deltay)
1978 LocationType x, y, dx, dy;
1980 /* save old crosshair position */
1981 x = Crosshair.X;
1982 y = Crosshair.Y;
1983 dx = (LocationType) (atoi (deltax) * PCB->Grid);
1984 dy = (LocationType) (atoi (deltay) * PCB->Grid);
1985 MoveCrosshairRelative (TO_SCREEN_SIGN_X (dx), TO_SCREEN_SIGN_Y (dy));
1986 FitCrosshairIntoGrid (Crosshair.X, Crosshair.Y);
1987 /* restore crosshair for erasure */
1988 Crosshair.X = x;
1989 Crosshair.Y = y;
1990 HideCrosshair (False);
1991 MoveCrosshairRelative (TO_SCREEN_SIGN_X (dx), TO_SCREEN_SIGN_Y (dy));
1992 /* update object position and cursor location */
1993 AdjustAttachedObjects ();
1994 RestoreCrosshair (False);
1997 /* ---------------------------------------------------------------------------
1998 * !!! no action routine !!!
2000 * event handler to set the cursor according to the X pointer position
2001 * called from inside main.c
2003 void
2004 EventMoveCrosshair (int ev_x, int ev_y)
2006 #ifdef HAVE_LIBSTROKE
2007 if (mid_stroke)
2009 StrokeBox.X2 = TO_PCB_X (ev_x);
2010 StrokeBox.Y2 = TO_PCB_Y (ev_y);
2011 stroke_record (Event->x, ev_y);
2012 return;
2014 #endif /* HAVE_LIBSTROKE */
2015 /* ignore events that are caused by ActionMovePointer */
2016 if (!IgnoreMotionEvents)
2018 if (MoveCrosshairAbsolute (ev_x, ev_y))
2021 /* update object position and cursor location */
2022 AdjustAttachedObjects ();
2023 RestoreCrosshair (False);
2026 else
2027 IgnoreMotionEvents = False;
2030 /* --------------------------------------------------------------------------- */
2032 static const char setvalue_syntax[] =
2033 "SetValue(Grid|Line|LineSize|Text|TextScale|ViaDrillingHole|Via|ViaSize, delta)";
2035 static const char setvalue_help[] =
2036 "Change various board-wide values and sizes.";
2038 /* %start-doc actions SetValue
2040 @table @code
2042 @item ViaDrillingHole
2043 Changes the diameter of the drill for new vias.
2045 @item Grid
2046 Sets the grid spacing.
2048 @item Line
2049 @item LineSize
2050 Changes the thickness of new lines.
2052 @item Via
2053 @item ViaSize
2054 Changes the diameter of new vias.
2056 @item Text
2057 @item TextScale
2058 Changes the size of new text.
2060 @end table
2062 %end-doc */
2064 static int
2065 ActionSetValue (int argc, char **argv, int x, int y)
2067 char *function = ARG (0);
2068 char *val = ARG (1);
2069 char *units = ARG (2);
2070 Boolean r; /* flag for 'relative' value */
2071 float value;
2072 int err = 0;
2074 if (function && val)
2076 HideCrosshair (True);
2077 value = GetValue (val, units, &r);
2078 switch (GetFunctionID (function))
2080 case F_ViaDrillingHole:
2081 SetViaDrillingHole (r ? value : value + Settings.ViaDrillingHole,
2082 False);
2083 hid_action ("RouteStylesChanged");
2084 break;
2086 case F_Grid:
2087 if (!r)
2089 if ((value == (int) value && PCB->Grid == (int) PCB->Grid)
2090 || (value != (int) value && PCB->Grid != (int) PCB->Grid))
2091 SetGrid (value + PCB->Grid, False);
2092 else
2093 Message (_
2094 ("Don't combine metric/English grids like that!\n"));
2096 else
2097 SetGrid (value, False);
2098 break;
2100 case F_LineSize:
2101 case F_Line:
2102 SetLineSize (r ? value : value + Settings.LineThickness);
2103 hid_action ("RouteStylesChanged");
2104 break;
2106 case F_Via:
2107 case F_ViaSize:
2108 SetViaSize (r ? value : value + Settings.ViaThickness, False);
2109 hid_action ("RouteStylesChanged");
2110 break;
2112 case F_Text:
2113 case F_TextScale:
2114 value /= 45;
2115 SetTextScale (r ? value : value + Settings.TextScale);
2116 break;
2117 default:
2118 err = 1;
2119 break;
2121 RestoreCrosshair (True);
2122 if (!err)
2123 return 0;
2126 AFAIL (setvalue);
2130 /* --------------------------------------------------------------------------- */
2132 static const char quit_syntax[] = "Quit()";
2134 static const char quit_help[] = "Quits the application.";
2136 /* %start-doc actions Quit
2138 If you have unsaved changes, you will be prompted to confirm before
2139 quitting.
2141 %end-doc */
2143 static int
2144 ActionQuit (int argc, char **argv, int x, int y)
2146 char *force = ARG (0);
2147 if (force && strcasecmp (force, "force") == 0)
2149 PCB->Changed = 0;
2150 exit (0);
2152 if (!PCB->Changed || gui->confirm_dialog (_("OK to lose data ?"), 0))
2153 QuitApplication ();
2154 return 1;
2157 /* --------------------------------------------------------------------------- */
2159 static const char connection_syntax[] =
2160 "Connection(Find|ResetLinesAndPolygons|ResetPinsAndVias|Reset)";
2162 static const char connection_help[] =
2163 "Searches connections of the object at the cursor position.";
2165 /* %start-doc actions Connection
2167 Connections found with this action will be highlighted in the
2168 ``connected-color'' color and will have the ``found'' flag set.
2170 @table @code
2172 @item Find
2173 The net under the cursor is ``found''.
2175 @item ResetLinesAndPolygons
2176 Any ``found'' lines and polygons are marked ``not found''.
2178 @item ResetPinsAndVias
2179 Any ``found'' pins and vias are marked ``not found''.
2181 @item Reset
2182 All ``found'' objects are marked ``not found''.
2184 @item Measure
2185 The net under the cursor is found and measured (the lengths of all
2186 line segments are added together)
2188 @end table
2190 %end-doc */
2192 static int
2193 ActionConnection (int argc, char **argv, int x, int y)
2195 char *function = ARG (0);
2196 if (function)
2198 HideCrosshair (True);
2199 switch (GetFunctionID (function))
2201 case F_Find:
2203 gui->get_coords ("Click on a connection", &x, &y);
2204 LookupConnection (x, y, True, PCB->Grid, FOUNDFLAG);
2205 break;
2208 case F_ResetLinesAndPolygons:
2209 ResetFoundLinesAndPolygons (True);
2210 break;
2212 case F_ResetPinsViasAndPads:
2213 ResetFoundPinsViasAndPads (True);
2214 break;
2216 case F_Reset:
2217 SaveUndoSerialNumber ();
2218 ResetFoundPinsViasAndPads (True);
2219 RestoreUndoSerialNumber ();
2220 ResetFoundLinesAndPolygons (True);
2221 break;
2223 RestoreCrosshair (True);
2224 return 0;
2227 AFAIL (connection);
2230 /* --------------------------------------------------------------------------- */
2232 static const char disperseelements_syntax[] =
2233 "DisperseElements(All|Selected)";
2235 static const char disperseelements_help[] = "Disperses elements.";
2237 /* %start-doc actions DisperseElements
2239 Normally this is used when starting a board, by selecting all elements
2240 and then dispersing them. This scatters the elements around the board
2241 so that you can pick individual ones, rather than have all the
2242 elements at the same 0,0 coordinate and thus impossible to choose
2243 from.
2245 %end-doc */
2247 #define GAP 10000
2249 static int
2250 ActionDisperseElements (int argc, char **argv, int x, int y)
2252 char *function = ARG (0);
2253 long minx, miny, maxx, maxy, dx, dy;
2254 int all = 0, bad = 0;
2256 minx = GAP;
2257 miny = GAP;
2258 maxx = GAP;
2259 maxy = GAP;
2261 if (!function || !*function)
2263 bad = 1;
2265 else
2267 switch (GetFunctionID (function))
2269 case F_All:
2270 all = 1;
2271 break;
2273 case F_Selected:
2274 all = 0;
2275 break;
2277 default:
2278 bad = 1;
2282 if (bad)
2284 AFAIL (disperseelements);
2288 ELEMENT_LOOP (PCB->Data);
2291 * If we want to disperse selected elements, maybe we need smarter
2292 * code here to avoid putting components on top of others which
2293 * are not selected. For now, I'm assuming that this is typically
2294 * going to be used either with a brand new design or a scratch
2295 * design holding some new components
2297 if (all || TEST_FLAG (SELECTEDFLAG, element))
2300 /* figure out how much to move the element */
2301 dx = minx - element->BoundingBox.X1;
2303 /* snap to the grid */
2304 dx -= (element->MarkX + dx) % (long) (PCB->Grid);
2307 * and add one grid size so we make sure we always space by GAP or
2308 * more
2310 dx += (long) (PCB->Grid);
2312 /* Figure out if this row has room. If not, start a new row */
2313 if (GAP + element->BoundingBox.X2 + dx > PCB->MaxWidth)
2315 miny = maxy + GAP;
2316 minx = GAP;
2319 /* figure out how much to move the element */
2320 dx = minx - element->BoundingBox.X1;
2321 dy = miny - element->BoundingBox.Y1;
2323 /* snap to the grid */
2324 dx -= (element->MarkX + dx) % (long) (PCB->Grid);
2325 dx += (long) (PCB->Grid);
2326 dy -= (element->MarkY + dy) % (long) (PCB->Grid);
2327 dy += (long) (PCB->Grid);
2329 /* move the element */
2330 MoveElementLowLevel (PCB->Data, element, dx, dy);
2332 /* and add to the undo list so we can undo this operation */
2333 AddObjectToMoveUndoList (ELEMENT_TYPE, NULL, NULL, element, dx, dy);
2335 /* keep track of how tall this row is */
2336 minx += element->BoundingBox.X2 - element->BoundingBox.X1 + GAP;
2337 if (maxy < element->BoundingBox.Y2)
2339 maxy = element->BoundingBox.Y2;
2344 END_LOOP;
2346 /* done with our action so increment the undo # */
2347 IncrementUndoSerialNumber ();
2349 ClearAndRedrawOutput ();
2350 SetChangedFlag (True);
2352 return 0;
2355 #undef GAP
2357 /* --------------------------------------------------------------------------- */
2359 static const char display_syntax[] =
2360 "Display(NameOnPCB|Description|Value)\n"
2361 "Display(Grid|Redraw)\n"
2362 "Display(CycleClip|Toggle45Degree|ToggleStartDirection)\n"
2363 "Display(ToggleGrid|ToggleRubberBandMode|ToggleUniqueNames)\n"
2364 "Display(ToggleMask|ToggleName|ToggleClearLine|ToggleSnapPin)\n"
2365 "Display(ToggleThindraw|ToggleThindrawPoly|ToggleOrthoMove|ToggleLocalRef)\n"
2366 "Display(ToggleCheckPlanes|ToggleShowDRC|ToggleAutoDRC)\n"
2367 "Display(ToggleLiveRoute|LockNames|OnlyNames)\n"
2368 "Display(Pinout|PinOrPadName)\n" "Display(Scroll, Direction)";
2370 static const char display_help[] = "Several display-related actions.";
2372 /* %start-doc actions Display
2374 @table @code
2376 @item NameOnPCB
2377 @item Description
2378 @item Value
2379 Specify whether all elements show their name, description, or value.
2381 @item Redraw
2382 Redraw the whole board.
2384 @item Toggle45Degree
2385 When clear, lines can be drawn at any angle. When set, lines are
2386 restricted to multiples of 45 degrees and requested lines may be
2387 broken up according to the clip setting.
2389 @item CycleClip
2390 Changes the way lines are restricted to 45 degree increments. The
2391 various settings are: straight only, orthogonal then angled, and angled
2392 then orthogonal. If AllDirections is set, this action disables it.
2394 @item ToggleRubberBandMode
2395 If set, moving an object moves all the lines attached to it too.
2397 @item ToggleStartDirection
2398 If set, each time you set a point in a line, the Clip toggles between
2399 orth-angle and angle-ortho.
2401 @item ToggleUniqueNames
2402 If set, you will not be permitted to change the name of an element to
2403 match that of another element.
2405 @item ToggleSnapPin
2406 If set, pin centers and pad end points are treated as additional grid
2407 points that the cursor can snap to.
2409 @item ToggleLocalRef
2410 If set, the mark is automatically set to the beginning of any move, so
2411 you can see the relative distance you've moved.
2413 @item ToggleThindraw
2414 If set, objects on the screen are drawn as outlines (lines are drawn
2415 as center-lines). This lets you see line endpoints hidden under pins,
2416 for example.
2418 @item ToggleThindrawPoly
2419 If set, polygons on the screen are drawn as outlines.
2421 @item ToggleShowDRC
2422 If set, pending objects (i.e. lines you're in the process of drawing)
2423 will be drawn with an outline showing how far away from other copper
2424 you need to be.
2426 @item ToggleLiveRoute
2427 If set, the progress of the autorouter will be visible on the screen.
2429 @item ToggleAutoDRC
2430 If set, you will not be permitted to make connections which violate
2431 the current DRC and netlist settings.
2433 @item ToggleCheckPlanes
2434 If set, lines and arcs aren't drawn, which usually leaves just the
2435 polygons. If you also disable all but the layer you're interested in,
2436 this allows you to check for isolated regions.
2438 @item ToggleOrthoMove
2439 If set, the crosshair is only allowed to move orthogonally from its
2440 previous position. I.e. you can move an element or line up, down,
2441 left, or right, but not up+left or down+right.
2443 @item ToggleName
2444 Selects whether the pinouts show the pin names or the pin numbers.
2446 @item ToggleMask
2447 Turns the solder mask on or off.
2449 @item ToggleClearLine
2450 When set, the clear-line flag causes new lines and arcs to have their
2451 ``clear polygons'' flag set, so they won't be electrically connected
2452 to any polygons they overlap.
2454 @item ToggleGrid
2455 Resets the origin of the current grid to be wherever the mouse pointer
2456 is (not where the crosshair currently is). If you provide two numbers
2457 after this, the origin is set to that coordinate. The numbers are in
2458 PCB internal units, currently 1/100 mil.
2460 @item Grid
2461 Toggles whether the grid is displayed or not.
2463 @item Pinout
2464 Causes the pinout of the element indicated by the cursor to be
2465 displayed, usually in a separate window.
2467 @item PinOrPadName
2468 Toggles whether the names of pins, pads, or (yes) vias will be
2469 displayed. If the cursor is over an element, all of its pins and pads
2470 are affected.
2472 @item Step <direction> <amount> <units>
2473 Steps the crosshair in the given direction, with 1=down/left, 2=down,
2474 etc, according to the numeric keypad layout. If amount is not given,
2475 the crosshair steps along the grid.
2477 @end table
2479 %end-doc */
2481 static int
2482 ActionDisplay (int argc, char **argv, int childX, int childY)
2484 char *function, *str_dir;
2485 int id;
2486 int err = 0;
2488 function = ARG (0);
2489 str_dir = ARG (1);
2491 if (function && (!str_dir || !*str_dir))
2493 HideCrosshair (True);
2494 switch (id = GetFunctionID (function))
2497 /* redraw layout with clearing the background */
2498 case F_ClearAndRedraw:
2499 gui->invalidate_all();
2500 break;
2502 /* redraw layout without clearing the background */
2503 case F_Redraw:
2505 BoxType area;
2506 area.X1 = 0;
2507 area.Y1 = 0;
2508 area.X2 = Output.Width;
2509 area.Y2 = Output.Height;
2510 RedrawOutput (&area);
2511 break;
2514 /* change the displayed name of elements */
2515 case F_Value:
2516 case F_NameOnPCB:
2517 case F_Description:
2518 ELEMENT_LOOP (PCB->Data);
2520 EraseElementName (element);
2522 END_LOOP;
2523 CLEAR_FLAG (DESCRIPTIONFLAG | NAMEONPCBFLAG, PCB);
2524 switch (id)
2526 case F_Value:
2527 break;
2528 case F_NameOnPCB:
2529 SET_FLAG (NAMEONPCBFLAG, PCB);
2530 break;
2531 case F_Description:
2532 SET_FLAG (DESCRIPTIONFLAG, PCB);
2533 break;
2535 ELEMENT_LOOP (PCB->Data);
2537 DrawElementName (element, 0);
2539 END_LOOP;
2540 Draw ();
2541 break;
2543 /* toggle line-adjust flag */
2544 case F_ToggleAllDirections:
2545 TOGGLE_FLAG (ALLDIRECTIONFLAG, PCB);
2546 AdjustAttachedObjects ();
2547 break;
2549 case F_CycleClip:
2550 if TEST_FLAG
2551 (ALLDIRECTIONFLAG, PCB)
2553 TOGGLE_FLAG (ALLDIRECTIONFLAG, PCB);
2554 PCB->Clipping = 0;
2556 else
2557 PCB->Clipping = (PCB->Clipping + 1) % 3;
2558 AdjustAttachedObjects ();
2559 break;
2561 case F_ToggleRubberBandMode:
2562 TOGGLE_FLAG (RUBBERBANDFLAG, PCB);
2563 break;
2565 case F_ToggleStartDirection:
2566 TOGGLE_FLAG (SWAPSTARTDIRFLAG, PCB);
2567 break;
2569 case F_ToggleUniqueNames:
2570 TOGGLE_FLAG (UNIQUENAMEFLAG, PCB);
2571 break;
2573 case F_ToggleSnapPin:
2574 TOGGLE_FLAG (SNAPPINFLAG, PCB);
2575 break;
2577 case F_ToggleLocalRef:
2578 TOGGLE_FLAG (LOCALREFFLAG, PCB);
2579 break;
2581 case F_ToggleThindraw:
2582 TOGGLE_FLAG (THINDRAWFLAG, PCB);
2583 ClearAndRedrawOutput ();
2584 break;
2586 case F_ToggleThindrawPoly:
2587 TOGGLE_FLAG (THINDRAWPOLYFLAG, PCB);
2588 ClearAndRedrawOutput ();
2589 break;
2591 case F_ToggleLockNames:
2592 TOGGLE_FLAG (LOCKNAMESFLAG, PCB);
2593 CLEAR_FLAG (ONLYNAMESFLAG, PCB);
2594 break;
2596 case F_ToggleOnlyNames:
2597 TOGGLE_FLAG (ONLYNAMESFLAG, PCB);
2598 CLEAR_FLAG (LOCKNAMESFLAG, PCB);
2599 break;
2601 case F_ToggleShowDRC:
2602 TOGGLE_FLAG (SHOWDRCFLAG, PCB);
2603 break;
2605 case F_ToggleLiveRoute:
2606 TOGGLE_FLAG (LIVEROUTEFLAG, PCB);
2607 break;
2609 case F_ToggleAutoDRC:
2610 TOGGLE_FLAG (AUTODRCFLAG, PCB);
2611 if (TEST_FLAG (AUTODRCFLAG, PCB) && Settings.Mode == LINE_MODE)
2613 SaveUndoSerialNumber ();
2614 ResetFoundPinsViasAndPads (True);
2615 RestoreUndoSerialNumber ();
2616 ResetFoundLinesAndPolygons (True);
2617 if (Crosshair.AttachedLine.State != STATE_FIRST)
2618 LookupConnection (Crosshair.AttachedLine.Point1.X,
2619 Crosshair.AttachedLine.Point1.Y, True, 1,
2620 FOUNDFLAG);
2622 break;
2624 case F_ToggleCheckPlanes:
2625 TOGGLE_FLAG (CHECKPLANESFLAG, PCB);
2626 ClearAndRedrawOutput ();
2627 break;
2629 case F_ToggleOrthoMove:
2630 TOGGLE_FLAG (ORTHOMOVEFLAG, PCB);
2631 break;
2633 case F_ToggleName:
2634 TOGGLE_FLAG (SHOWNUMBERFLAG, PCB);
2635 UpdateAll ();
2636 break;
2638 case F_ToggleMask:
2639 TOGGLE_FLAG (SHOWMASKFLAG, PCB);
2640 UpdateAll ();
2641 break;
2643 case F_ToggleClearLine:
2644 TOGGLE_FLAG (CLEARNEWFLAG, PCB);
2645 break;
2647 /* shift grid alignment */
2648 case F_ToggleGrid:
2650 float oldGrid;
2652 oldGrid = PCB->Grid;
2653 PCB->Grid = 1.0;
2654 if (MoveCrosshairAbsolute (childX, childY))
2655 RestoreCrosshair (False); /* was hidden by MoveCrosshairAbs */
2656 SetGrid (oldGrid, True);
2658 break;
2660 /* toggle displaying of the grid */
2661 case F_Grid:
2662 Settings.DrawGrid = !Settings.DrawGrid;
2663 UpdateAll ();
2664 break;
2666 /* display the pinout of an element */
2667 case F_Pinout:
2669 ElementTypePtr element;
2670 void *ptrtmp;
2672 if ((SearchScreen
2673 (Crosshair.X, Crosshair.Y, ELEMENT_TYPE, &ptrtmp,
2674 &ptrtmp, &ptrtmp)) != NO_TYPE)
2676 element = (ElementTypePtr) ptrtmp;
2677 gui->show_item (element);
2679 break;
2682 /* toggle displaying of pin/pad/via names */
2683 case F_PinOrPadName:
2685 void *ptr1, *ptr2, *ptr3;
2687 switch (SearchScreen (Crosshair.X, Crosshair.Y,
2688 ELEMENT_TYPE | PIN_TYPE | PAD_TYPE |
2689 VIA_TYPE, (void **) &ptr1, (void **) &ptr2,
2690 (void **) &ptr3))
2692 case ELEMENT_TYPE:
2693 PIN_LOOP ((ElementTypePtr) ptr1);
2695 if (TEST_FLAG (DISPLAYNAMEFLAG, pin))
2696 ErasePinName (pin);
2697 else
2698 DrawPinName (pin, 0);
2699 AddObjectToFlagUndoList (PIN_TYPE, ptr1, pin, pin);
2700 TOGGLE_FLAG (DISPLAYNAMEFLAG, pin);
2702 END_LOOP;
2703 PAD_LOOP ((ElementTypePtr) ptr1);
2705 if (TEST_FLAG (DISPLAYNAMEFLAG, pad))
2706 ErasePadName (pad);
2707 else
2708 DrawPadName (pad, 0);
2709 AddObjectToFlagUndoList (PAD_TYPE, ptr1, pad, pad);
2710 TOGGLE_FLAG (DISPLAYNAMEFLAG, pad);
2712 END_LOOP;
2713 SetChangedFlag (True);
2714 IncrementUndoSerialNumber ();
2715 Draw ();
2716 break;
2718 case PIN_TYPE:
2719 if (TEST_FLAG (DISPLAYNAMEFLAG, (PinTypePtr) ptr2))
2720 ErasePinName ((PinTypePtr) ptr2);
2721 else
2722 DrawPinName ((PinTypePtr) ptr2, 0);
2723 AddObjectToFlagUndoList (PIN_TYPE, ptr1, ptr2, ptr3);
2724 TOGGLE_FLAG (DISPLAYNAMEFLAG, (PinTypePtr) ptr2);
2725 SetChangedFlag (True);
2726 IncrementUndoSerialNumber ();
2727 Draw ();
2728 break;
2730 case PAD_TYPE:
2731 if (TEST_FLAG (DISPLAYNAMEFLAG, (PadTypePtr) ptr2))
2732 ErasePadName ((PadTypePtr) ptr2);
2733 else
2734 DrawPadName ((PadTypePtr) ptr2, 0);
2735 AddObjectToFlagUndoList (PAD_TYPE, ptr1, ptr2, ptr3);
2736 TOGGLE_FLAG (DISPLAYNAMEFLAG, (PadTypePtr) ptr2);
2737 SetChangedFlag (True);
2738 IncrementUndoSerialNumber ();
2739 Draw ();
2740 break;
2741 case VIA_TYPE:
2742 if (TEST_FLAG (DISPLAYNAMEFLAG, (PinTypePtr) ptr2))
2743 EraseViaName ((PinTypePtr) ptr2);
2744 else
2745 DrawViaName ((PinTypePtr) ptr2, 0);
2746 AddObjectToFlagUndoList (VIA_TYPE, ptr1, ptr2, ptr3);
2747 TOGGLE_FLAG (DISPLAYNAMEFLAG, (PinTypePtr) ptr2);
2748 SetChangedFlag (True);
2749 IncrementUndoSerialNumber ();
2750 Draw ();
2751 break;
2753 break;
2755 default:
2756 err = 1;
2758 RestoreCrosshair (True);
2760 else if (function && str_dir)
2762 switch (GetFunctionID (function))
2764 case F_ToggleGrid:
2765 if (argc > 2)
2767 /* FIXME: units */
2768 PCB->GridOffsetX = atoi (argv[1]);
2769 PCB->GridOffsetY = atoi (argv[2]);
2770 if (Settings.DrawGrid)
2771 UpdateAll ();
2773 break;
2775 default:
2776 err = 1;
2777 break;
2781 if (!err)
2782 return 0;
2784 AFAIL (display);
2787 /* --------------------------------------------------------------------------- */
2789 static const char mode_syntax[] =
2790 "Mode(Arc|Arrow|Copy|InsertPoint|Line|Lock|Move|None|PasteBuffer)\n"
2791 "Mode(Polygon|Rectangle|Remove|Rotate|Text|Thermal|Via)\n"
2792 "Mode(Notify|Release|Cancel|Stroke)\n" "Mode(Save|Restore)";
2794 static const char mode_help[] = "Change or use the tool mode.";
2796 /* %start-doc actions Mode
2798 @table @code
2800 @item Arc
2801 @itemx Arrow
2802 @itemx Copy
2803 @itemx InsertPoint
2804 @itemx Line
2805 @itemx Lock
2806 @itemx Move
2807 @itemx None
2808 @itemx PasteBuffer
2809 @itemx Polygon
2810 @itemx Rectangle
2811 @itemx Remove
2812 @itemx Rotate
2813 @itemx Text
2814 @itemx Thermal
2815 @itemx Via
2816 Select the indicated tool.
2818 @item Notify
2819 Called when you press the mouse button, or move the mouse.
2821 @item Release
2822 Called when you release the mouse button.
2824 @item Cancel
2825 Cancels any pending tool activity, allowing you to restart elsewhere.
2826 For example, this allows you to start a new line rather than attach a
2827 line to the previous line.
2829 @item Escape
2830 Similar to Cancel but calling this action a second time will return
2831 to the Arrow tool.
2833 @item Stroke
2834 If your @code{pcb} was built with libstroke, this invokes the stroke
2835 input method. If not, this will restart a drawing mode if you were
2836 drawing, else it will select objects.
2838 @item Save
2839 Remembers the current tool.
2841 @item Restore
2842 Restores the tool to the last saved tool.
2844 @end table
2846 %end-doc */
2848 static int
2849 ActionMode (int argc, char **argv, int x, int y)
2851 char *function = ARG (0);
2853 if (function)
2855 Note.X = Crosshair.X;
2856 Note.Y = Crosshair.Y;
2857 HideCrosshair (True);
2858 switch (GetFunctionID (function))
2860 case F_Arc:
2861 SetMode (ARC_MODE);
2862 break;
2863 case F_Arrow:
2864 SetMode (ARROW_MODE);
2865 break;
2866 case F_Copy:
2867 SetMode (COPY_MODE);
2868 break;
2869 case F_InsertPoint:
2870 SetMode (INSERTPOINT_MODE);
2871 break;
2872 case F_Line:
2873 SetMode (LINE_MODE);
2874 break;
2875 case F_Lock:
2876 SetMode (LOCK_MODE);
2877 break;
2878 case F_Move:
2879 SetMode (MOVE_MODE);
2880 break;
2881 case F_None:
2882 SetMode (NO_MODE);
2883 break;
2884 case F_Cancel:
2886 int saved_mode = Settings.Mode;
2887 SetMode (NO_MODE);
2888 SetMode (saved_mode);
2890 break;
2891 case F_Escape:
2893 switch (Settings.Mode)
2895 case VIA_MODE:
2896 case PASTEBUFFER_MODE:
2897 case TEXT_MODE:
2898 case ROTATE_MODE:
2899 case REMOVE_MODE:
2900 case MOVE_MODE:
2901 case COPY_MODE:
2902 case INSERTPOINT_MODE:
2903 case RUBBERBANDMOVE_MODE:
2904 case THERMAL_MODE:
2905 case LOCK_MODE:
2906 SetMode (NO_MODE);
2907 SetMode (ARROW_MODE);
2908 break;
2910 case LINE_MODE:
2911 if (Crosshair.AttachedLine.State == STATE_FIRST)
2912 SetMode (ARROW_MODE);
2913 else
2915 SetMode (NO_MODE);
2916 SetMode (LINE_MODE);
2918 break;
2920 case RECTANGLE_MODE:
2921 if (Crosshair.AttachedBox.State == STATE_FIRST)
2922 SetMode (ARROW_MODE);
2923 else
2925 SetMode (NO_MODE);
2926 SetMode (RECTANGLE_MODE);
2928 break;
2930 case POLYGON_MODE:
2931 if (Crosshair.AttachedLine.State == STATE_FIRST)
2932 SetMode (ARROW_MODE);
2933 else
2935 SetMode (NO_MODE);
2936 SetMode (POLYGON_MODE);
2938 break;
2940 case ARC_MODE:
2941 if (Crosshair.AttachedBox.State == STATE_FIRST)
2942 SetMode (ARROW_MODE);
2943 else
2945 SetMode (NO_MODE);
2946 SetMode (ARC_MODE);
2948 break;
2950 case ARROW_MODE:
2951 break;
2953 default:
2954 break;
2957 break;
2959 case F_Notify:
2960 NotifyMode ();
2961 break;
2962 case F_PasteBuffer:
2963 SetMode (PASTEBUFFER_MODE);
2964 break;
2965 case F_Polygon:
2966 SetMode (POLYGON_MODE);
2967 break;
2968 #ifndef HAVE_LIBSTROKE
2969 case F_Release:
2970 ReleaseMode ();
2971 break;
2972 #else
2973 case F_Release:
2974 if (mid_stroke)
2975 FinishStroke ();
2976 else
2977 ReleaseMode ();
2978 break;
2979 #endif
2980 case F_Remove:
2981 SetMode (REMOVE_MODE);
2982 break;
2983 case F_Rectangle:
2984 SetMode (RECTANGLE_MODE);
2985 break;
2986 case F_Rotate:
2987 SetMode (ROTATE_MODE);
2988 break;
2989 case F_Stroke:
2990 #ifdef HAVE_LIBSTROKE
2991 mid_stroke = True;
2992 StrokeBox.X1 = Crosshair.X;
2993 StrokeBox.Y1 = Crosshair.Y;
2994 break;
2995 #else
2996 /* Handle middle mouse button restarts of drawing mode. If not in
2997 | a drawing mode, middle mouse button will select objects.
2999 if (Settings.Mode == LINE_MODE
3000 && Crosshair.AttachedLine.State != STATE_FIRST)
3002 SetMode (LINE_MODE);
3004 else if (Settings.Mode == ARC_MODE
3005 && Crosshair.AttachedBox.State != STATE_FIRST)
3006 SetMode (ARC_MODE);
3007 else if (Settings.Mode == RECTANGLE_MODE
3008 && Crosshair.AttachedBox.State != STATE_FIRST)
3009 SetMode (RECTANGLE_MODE);
3010 else if (Settings.Mode == POLYGON_MODE
3011 && Crosshair.AttachedLine.State != STATE_FIRST)
3012 SetMode (POLYGON_MODE);
3013 else
3015 SaveMode ();
3016 saved_mode = True;
3017 SetMode (ARROW_MODE);
3018 NotifyMode ();
3020 break;
3021 #endif
3022 case F_Text:
3023 SetMode (TEXT_MODE);
3024 break;
3025 case F_Thermal:
3026 SetMode (THERMAL_MODE);
3027 break;
3028 case F_Via:
3029 SetMode (VIA_MODE);
3030 break;
3032 case F_Restore: /* restore the last saved mode */
3033 RestoreMode ();
3034 break;
3036 case F_Save: /* save currently selected mode */
3037 SaveMode ();
3038 break;
3040 RestoreCrosshair (True);
3041 return 0;
3044 AFAIL (mode);
3047 /* --------------------------------------------------------------------------- */
3049 static const char removeselected_syntax[] = "RemoveSelected()";
3051 static const char removeselected_help[] = "Removes any selected objects.";
3053 /* %start-doc actions RemoveSelected
3055 %end-doc */
3057 static int
3058 ActionRemoveSelected (int argc, char **argv, int x, int y)
3060 HideCrosshair (True);
3061 if (RemoveSelected ())
3062 SetChangedFlag (True);
3063 RestoreCrosshair (True);
3064 return 0;
3067 /* --------------------------------------------------------------------------- */
3069 static const char renumber_syntax[] = "Renumber()\n" "Renumber(filename)";
3071 static const char renumber_help[] =
3072 "Renumber all elements. The changes will be recorded to filename\n"
3073 "for use in backannotating these changes to the schematic.";
3075 /* %start-doc actions Renumber
3077 %end-doc */
3079 static int
3080 ActionRenumber (int argc, char **argv, int x, int y)
3082 Boolean changed = False;
3083 ElementTypePtr *element_list;
3084 ElementTypePtr *locked_element_list;
3085 unsigned int i, j, k, cnt, lock_cnt;
3086 unsigned int tmpi;
3087 size_t sz;
3088 char *tmps;
3089 char *name;
3090 FILE *out;
3091 size_t cnt_list_sz = 100;
3092 struct _cnt_list
3094 char *name;
3095 unsigned int cnt;
3096 } *cnt_list;
3097 char **was, **is, *pin;
3098 unsigned int c_cnt = 0;
3099 int unique, ok;
3101 if (argc < 1)
3102 name = gui->prompt_for ("Renumber annotation file:", 0);
3103 else
3104 name = argv[0];
3106 if ((out = fopen (name, "r")))
3108 fclose (out);
3109 if (!gui->confirm_dialog (_("File exists! Ok to overwrite?"), 0))
3110 return 0;
3112 if ((out = fopen (name, "w")) == NULL)
3114 Message ("Could not open %s\n", name);
3115 return 1;
3118 fprintf (out, "*COMMENT* PCB Annotation File\n");
3119 fprintf (out, "*FILEVERSION* 20061031\n");
3122 * Make a first pass through all of the elements and sort them out
3123 * by location on the board. While here we also collect a list of
3124 * locked elements.
3126 * We'll actually renumber things in the 2nd pass.
3128 element_list = calloc (PCB->Data->ElementN, sizeof (ElementTypePtr));
3129 locked_element_list = calloc (PCB->Data->ElementN, sizeof (ElementTypePtr));
3130 was = calloc (PCB->Data->ElementN, sizeof (char *));
3131 is = calloc (PCB->Data->ElementN, sizeof (char *));
3132 if (element_list == NULL || locked_element_list == NULL || was == NULL
3133 || is == NULL)
3135 fprintf (stderr, "calloc() failed in %s\n", __FUNCTION__);
3136 exit (1);
3140 cnt = 0;
3141 lock_cnt = 0;
3142 ELEMENT_LOOP (PCB->Data);
3144 if (TEST_FLAG (LOCKFLAG, element->Name) || TEST_FLAG (LOCKFLAG, element))
3147 * add to the list of locked elements which we won't try to
3148 * renumber and whose reference designators are now reserved.
3150 fprintf (out,
3151 "*WARN* Element \"%s\" at (%d,%d) is locked and will not be renumbered.\n",
3152 UNKNOWN (NAMEONPCB_NAME (element)), element->MarkX,
3153 element->MarkY);
3154 locked_element_list[lock_cnt] = element;
3155 lock_cnt++;
3158 else
3160 /* count of devices which will be renumbered */
3161 cnt++;
3163 /* search for correct position in the list */
3164 i = 0;
3165 while (element_list[i] && element->MarkY > element_list[i]->MarkY)
3166 i++;
3169 * We have found the position where we have the first element that
3170 * has the same Y value or a lower Y value. Now move forward if
3171 * needed through the X values
3173 while (element_list[i]
3174 && element->MarkY == element_list[i]->MarkY
3175 && element->MarkX > element_list[i]->MarkX)
3176 i++;
3178 for (j = cnt - 1; j > i; j--)
3180 element_list[j] = element_list[j - 1];
3182 element_list[i] = element;
3185 END_LOOP;
3189 * Now that the elements are sorted by board position, we go through
3190 * and renumber them.
3194 * turn off the flag which requires unique names so it doesn't get
3195 * in our way. When we're done with the renumber we will have unique
3196 * names.
3198 unique = TEST_FLAG (UNIQUENAMEFLAG, PCB);
3199 CLEAR_FLAG (UNIQUENAMEFLAG, PCB);
3201 cnt_list = calloc (cnt_list_sz, sizeof (struct _cnt_list));
3202 for (i = 0; i < cnt; i++)
3204 /* If there is no refdes, maybe just spit out a warning */
3205 if (NAMEONPCB_NAME (element_list[i]))
3207 /* figure out the prefix */
3208 tmps = strdup (NAMEONPCB_NAME (element_list[i]));
3209 j = 0;
3210 while (tmps[j] && (tmps[j] < '0' || tmps[j] > '9')
3211 && tmps[j] != '?')
3212 j++;
3213 tmps[j] = '\0';
3215 /* check the counter for this prefix */
3216 for (j = 0;
3217 cnt_list[j].name && (strcmp (cnt_list[j].name, tmps) != 0)
3218 && j < cnt_list_sz; j++);
3220 /* grow the list if needed */
3221 if (j == cnt_list_sz)
3223 cnt_list_sz += 100;
3224 cnt_list = realloc (cnt_list, cnt_list_sz);
3225 if (cnt_list == NULL)
3227 fprintf (stderr, "realloc failed() in %s\n", __FUNCTION__);
3228 exit (1);
3230 /* zero out the memory that we added */
3231 for (tmpi = j; tmpi < cnt_list_sz; tmpi++)
3233 cnt_list[tmpi].name = NULL;
3234 cnt_list[tmpi].cnt = 0;
3239 * start a new counter if we don't have a counter for this
3240 * prefix
3242 if (!cnt_list[j].name)
3244 cnt_list[j].name = strdup (tmps);
3245 cnt_list[j].cnt = 0;
3249 * check to see if the new refdes is already used by a
3250 * locked element
3254 ok = 1;
3255 cnt_list[j].cnt++;
3256 free (tmps);
3258 /* space for the prefix plus 1 digit plus the '\0' */
3259 sz = strlen (cnt_list[j].name) + 2;
3261 /* and 1 more per extra digit needed to hold the number */
3262 tmpi = cnt_list[j].cnt;
3263 while (tmpi > 10)
3265 sz++;
3266 tmpi = tmpi / 10;
3268 tmps = malloc (sz * sizeof (char));
3269 sprintf (tmps, "%s%d", cnt_list[j].name, cnt_list[j].cnt);
3272 * now compare to the list of reserved (by locked
3273 * elements) names
3275 for (k = 0; k < lock_cnt; k++)
3277 if (strcmp
3278 (UNKNOWN (NAMEONPCB_NAME (locked_element_list[k])),
3279 tmps) == 0)
3281 ok = 0;
3282 break;
3287 while (!ok);
3289 if (strcmp (tmps, NAMEONPCB_NAME (element_list[i])) != 0)
3291 fprintf (out, "*RENAME* \"%s\" \"%s\"\n",
3292 NAMEONPCB_NAME (element_list[i]), tmps);
3294 /* add this rename to our table of renames so we can update the netlist */
3295 was[c_cnt] = strdup (NAMEONPCB_NAME (element_list[i]));
3296 is[c_cnt] = strdup (tmps);
3297 c_cnt++;
3299 AddObjectToChangeNameUndoList (ELEMENT_TYPE, NULL, NULL,
3300 element_list[i],
3301 NAMEONPCB_NAME (element_list
3302 [i]));
3304 ChangeObjectName (ELEMENT_TYPE, element_list[i], NULL, NULL,
3305 tmps);
3306 changed = True;
3308 /* we don't free tmps in this case because it is used */
3310 else
3311 free (tmps);
3313 else
3315 fprintf (out, "*WARN* Element at (%d,%d) has no name.\n",
3316 element_list[i]->MarkX, element_list[i]->MarkY);
3321 fclose (out);
3323 /* restore the unique flag setting */
3324 if (unique)
3325 SET_FLAG (UNIQUENAMEFLAG, PCB);
3327 if (changed)
3330 /* update the netlist */
3331 AddNetlistLibToUndoList (&(PCB->NetlistLib));
3333 /* iterate over each net */
3334 for (i = 0; i < PCB->NetlistLib.MenuN; i++)
3337 /* iterate over each pin on the net */
3338 for (j = 0; j < PCB->NetlistLib.Menu[i].EntryN; j++)
3341 /* figure out the pin number part from strings like U3-21 */
3342 tmps = strdup (PCB->NetlistLib.Menu[i].Entry[j].ListEntry);
3343 for (k = 0; tmps[k] && tmps[k] != '-'; k++);
3344 tmps[k] = '\0';
3345 pin = tmps + k + 1;
3347 /* iterate over the list of changed reference designators */
3348 for (k = 0; k < c_cnt; k++)
3351 * if the pin needs to change, change it and quit
3352 * searching in the list.
3354 if (strcmp (tmps, was[k]) == 0)
3356 free (PCB->NetlistLib.Menu[i].Entry[j].ListEntry);
3357 PCB->NetlistLib.Menu[i].Entry[j].ListEntry =
3358 malloc ((strlen (is[k]) + strlen (pin) +
3359 2) * sizeof (char));
3360 sprintf (PCB->NetlistLib.Menu[i].Entry[j].ListEntry,
3361 "%s-%s", is[k], pin);
3362 k = c_cnt;
3366 free (tmps);
3369 for (k = 0; k < c_cnt; k++)
3371 free (was[k]);
3372 free (is[k]);
3375 hid_action ("NetlistChanged");
3376 IncrementUndoSerialNumber ();
3377 SetChangedFlag (True);
3380 free (locked_element_list);
3381 free (element_list);
3382 free (cnt_list);
3383 return 0;
3387 /* --------------------------------------------------------------------------- */
3389 static const char ripup_syntax[] = "RipUp(All|Selected|Element)";
3391 static const char ripup_help[] =
3392 "Ripup auto-routed tracks, or convert an element to parts.";
3394 /* %start-doc actions RipUp
3396 @table @code
3398 @item All
3399 Removes all lines and vias which were created by the autorouter.
3401 @item Selected
3402 Removes all selected lines and vias which were created by the
3403 autorouter.
3405 @item Element
3406 Converts the element under the cursor to parts (vias and lines). Note
3407 that this uses the highest numbered paste buffer.
3409 @end table
3411 %end-doc */
3413 static int
3414 ActionRipUp (int argc, char **argv, int x, int y)
3416 char *function = ARG (0);
3417 Boolean changed = False;
3419 if (function)
3421 HideCrosshair (True);
3422 switch (GetFunctionID (function))
3424 case F_All:
3425 ALLLINE_LOOP (PCB->Data);
3427 if (TEST_FLAG (AUTOFLAG, line) && !TEST_FLAG (LOCKFLAG, line))
3429 RemoveObject (LINE_TYPE, layer, line, line);
3430 changed = True;
3433 ENDALL_LOOP;
3434 VIA_LOOP (PCB->Data);
3436 if (TEST_FLAG (AUTOFLAG, via) && !TEST_FLAG (LOCKFLAG, via))
3438 RemoveObject (VIA_TYPE, via, via, via);
3439 changed = True;
3442 END_LOOP;
3444 if (changed)
3446 IncrementUndoSerialNumber ();
3447 SetChangedFlag (True);
3449 break;
3450 case F_Selected:
3451 VISIBLELINE_LOOP (PCB->Data);
3453 if (TEST_FLAGS (AUTOFLAG | SELECTEDFLAG, line)
3454 && !TEST_FLAG (LOCKFLAG, line))
3456 RemoveObject (LINE_TYPE, layer, line, line);
3457 changed = True;
3460 ENDALL_LOOP;
3461 if (PCB->ViaOn)
3462 VIA_LOOP (PCB->Data);
3464 if (TEST_FLAGS (AUTOFLAG | SELECTEDFLAG, via)
3465 && !TEST_FLAG (LOCKFLAG, via))
3467 RemoveObject (VIA_TYPE, via, via, via);
3468 changed = True;
3471 END_LOOP;
3472 if (changed)
3474 IncrementUndoSerialNumber ();
3475 SetChangedFlag (True);
3477 break;
3478 case F_Element:
3480 void *ptr1, *ptr2, *ptr3;
3482 if (SearchScreen (Crosshair.X, Crosshair.Y, ELEMENT_TYPE,
3483 &ptr1, &ptr2, &ptr3) != NO_TYPE)
3485 Note.Buffer = Settings.BufferNumber;
3486 SetBufferNumber (MAX_BUFFER - 1);
3487 ClearBuffer (PASTEBUFFER);
3488 CopyObjectToBuffer (PASTEBUFFER->Data, PCB->Data,
3489 ELEMENT_TYPE, ptr1, ptr2, ptr3);
3490 SmashBufferElement (PASTEBUFFER);
3491 PASTEBUFFER->X = 0;
3492 PASTEBUFFER->Y = 0;
3493 SaveUndoSerialNumber ();
3494 EraseObject (ELEMENT_TYPE, ptr1, ptr1);
3495 MoveObjectToRemoveUndoList (ELEMENT_TYPE, ptr1, ptr2, ptr3);
3496 RestoreUndoSerialNumber ();
3497 CopyPastebufferToLayout (0, 0);
3498 SetBufferNumber (Note.Buffer);
3499 SetChangedFlag (True);
3502 break;
3504 RestoreCrosshair (True);
3506 return 0;
3509 /* --------------------------------------------------------------------------- */
3511 static const char addrats_syntax[] = "AddRats(AllRats|SelectedRats|Close)";
3513 static const char addrats_help[] = "Add one or more rat lines to the board.";
3515 /* %start-doc actions AddRats
3517 @table @code
3519 @item AllRats
3520 Create rat lines for all loaded nets that aren't already connected on
3521 with copper.
3523 @item SelectedRats
3524 Similarly, but only add rat lines for nets connected to selected pins
3525 and pads.
3527 @item Close
3528 Selects the shortest unselected rat on the board.
3530 @end table
3532 %end-doc */
3534 static int
3535 ActionAddRats (int argc, char **argv, int x, int y)
3537 char *function = ARG (0);
3538 RatTypePtr shorty;
3539 float len, small;
3541 if (function)
3543 HideCrosshair (True);
3544 switch (GetFunctionID (function))
3546 case F_AllRats:
3547 if (AddAllRats (False, NULL))
3548 SetChangedFlag (True);
3549 break;
3550 case F_SelectedRats:
3551 case F_Selected:
3552 if (AddAllRats (True, NULL))
3553 SetChangedFlag (True);
3554 break;
3555 case F_Close:
3556 small = SQUARE (MAX_COORD);
3557 shorty = NULL;
3558 RAT_LOOP (PCB->Data);
3560 if (TEST_FLAG (SELECTEDFLAG, line))
3561 continue;
3562 len = SQUARE (line->Point1.X - line->Point2.X) +
3563 SQUARE (line->Point1.Y - line->Point2.Y);
3564 if (len < small)
3566 small = len;
3567 shorty = line;
3570 END_LOOP;
3571 if (shorty)
3573 AddObjectToFlagUndoList (RATLINE_TYPE, shorty, shorty, shorty);
3574 SET_FLAG (SELECTEDFLAG, shorty);
3575 DrawRat (shorty, 0);
3576 Draw ();
3577 CenterDisplay ((shorty->Point2.X + shorty->Point1.X) / 2,
3578 (shorty->Point2.Y + shorty->Point1.Y) / 2,
3579 False);
3581 break;
3583 RestoreCrosshair (True);
3585 return 0;
3588 /* --------------------------------------------------------------------------- */
3590 static const char deleterats_syntax[] =
3591 "DeleteRats(AllRats|Selected|SelectedRats)";
3593 static const char deleterats_help[] = "Delete rat lines.";
3595 /* %start-doc actions DeleteRats
3597 %end-doc */
3599 static int
3600 ActionDeleteRats (int argc, char **argv, int x, int y)
3602 char *function = ARG (0);
3603 if (function)
3605 HideCrosshair (True);
3606 switch (GetFunctionID (function))
3608 case F_AllRats:
3609 if (DeleteRats (False))
3610 SetChangedFlag (True);
3611 break;
3612 case F_SelectedRats:
3613 case F_Selected:
3614 if (DeleteRats (True))
3615 SetChangedFlag (True);
3616 break;
3618 RestoreCrosshair (True);
3620 return 0;
3623 /* --------------------------------------------------------------------------- */
3625 static const char autoplace_syntax[] = "AutoPlaceSelected()";
3627 static const char autoplace_help[] = "Auto-place selected components.";
3629 /* %start-doc actions AutoPlaceSelected
3631 Attempts to re-arrange the selected components such that the nets
3632 connecting them are minimized. Note that you cannot undo this.
3634 %end-doc */
3636 static int
3637 ActionAutoPlaceSelected (int argc, char **argv, int x, int y)
3639 hid_action("Busy");
3640 if (gui->confirm_dialog (_("Auto-placement can NOT be undone.\n"
3641 "Do you want to continue anyway?\n"), 0))
3643 HideCrosshair (True);
3644 if (AutoPlaceSelected ())
3645 SetChangedFlag (True);
3646 RestoreCrosshair (True);
3648 return 0;
3651 /* --------------------------------------------------------------------------- */
3653 static const char autoroute_syntax[] = "AutoRoute(AllRats|SelectedRats)";
3655 static const char autoroute_help[] = "Auto-route some or all rat lines.";
3657 /* %start-doc actions AutoRoute
3659 @table @code
3661 @item AllRats
3662 Attempt to autoroute all rats.
3664 @item SelectedRats
3665 Attempt to autoroute the selected rats.
3667 @end table
3669 Before autorouting, it's important to set up a few things. First,
3670 make sure any layers you aren't using are disabled, else the
3671 autorouter may use them. Next, make sure the current line and via
3672 styles are set accordingly. Last, make sure "new lines clear
3673 polygons" is set, in case you eventually want to add a copper pour.
3675 Autorouting takes a while. During this time, the program may not be
3676 responsive.
3678 %end-doc */
3680 static int
3681 ActionAutoRoute (int argc, char **argv, int x, int y)
3683 char *function = ARG (0);
3684 hid_action("Busy");
3685 if (function) /* one parameter */
3687 HideCrosshair (True);
3688 switch (GetFunctionID (function))
3690 case F_AllRats:
3691 if (AutoRoute (False))
3692 SetChangedFlag (True);
3693 break;
3694 case F_SelectedRats:
3695 case F_Selected:
3696 if (AutoRoute (True))
3697 SetChangedFlag (True);
3698 break;
3700 RestoreCrosshair (True);
3702 return 0;
3705 /* --------------------------------------------------------------------------- */
3707 static const char markcrosshair_syntax[] =
3708 "MarkCrosshair()\n" "MarkCrosshair(Center)";
3710 static const char markcrosshair_help[] = "Set/Reset the Crosshair mark";
3712 /* %start-doc actions MarkCrosshair
3714 The ``mark'' is a small X-shaped target on the display which is
3715 treated like a second origin (the normal origin is the upper let
3716 corner of the board). The GUI will display a second set of
3717 coordinates for this mark, which tells you how far you are from it.
3719 If no argument is given, the mark is toggled - disabled if it was
3720 enabled, or enabled at the current cursor position of disabled. If
3721 the @code{Center} argument is given, the mark is moved to the current
3722 cursor location.
3724 %end-doc */
3726 static int
3727 ActionMarkCrosshair (int argc, char **argv, int x, int y)
3729 char *function = ARG (0);
3730 if (!function || !*function)
3732 if (Marked.status)
3734 DrawMark (True);
3735 Marked.status = False;
3737 else
3739 Marked.status = True;
3740 Marked.X = Crosshair.X;
3741 Marked.Y = Crosshair.Y;
3742 DrawMark (False);
3745 else if (GetFunctionID (function) == F_Center)
3747 DrawMark (True);
3748 Marked.status = True;
3749 Marked.X = Crosshair.X;
3750 Marked.Y = Crosshair.Y;
3751 DrawMark (False);
3753 return 0;
3756 /* --------------------------------------------------------------------------- */
3758 static const char changesize_syntax[] =
3759 "ChangeSize(Object, delta)\n"
3760 "ChangeSize(SelectedObjects|Selected, delta)\n"
3761 "ChangeSize(SelectedLines|SelectedPins|SelectedVias, delta)\n"
3762 "ChangeSize(SelectedPads|SelectedTexts|SelectedNames, delta)\n"
3763 "ChangeSize(SelectedElements, delta)";
3765 static const char changesize_help[] = "Changes the size of objects.";
3767 /* %start-doc actions ChangeSize
3769 For lines and arcs, this changes the width. For pins and vias, this
3770 changes the overall diameter of the copper annulus. For pads, this
3771 changes the width and, indirectly, the length. For texts and names,
3772 this changes the scaling factor. For elements, this changes the width
3773 of the silk layer lines and arcs for this element.
3775 %end-doc */
3777 static int
3778 ActionChangeSize (int argc, char **argv, int x, int y)
3780 char *function = ARG (0);
3781 char *delta = ARG (1);
3782 char *units = ARG (2);
3783 Boolean r; /* indicates if absolute size is given */
3784 float value;
3786 if (function && delta)
3788 value = GetValue (delta, units, &r);
3789 HideCrosshair (True);
3790 switch (GetFunctionID (function))
3792 case F_Object:
3794 int type;
3795 void *ptr1, *ptr2, *ptr3;
3797 if ((type =
3798 SearchScreen (Crosshair.X, Crosshair.Y, CHANGESIZE_TYPES,
3799 &ptr1, &ptr2, &ptr3)) != NO_TYPE)
3800 if (TEST_FLAG (LOCKFLAG, (PinTypePtr) ptr2))
3801 Message (_("Sorry, the object is locked\n"));
3802 if (ChangeObjectSize (type, ptr1, ptr2, ptr3, value, r))
3803 SetChangedFlag (True);
3804 break;
3807 case F_SelectedVias:
3808 if (ChangeSelectedSize (VIA_TYPE, value, r))
3809 SetChangedFlag (True);
3810 break;
3812 case F_SelectedPins:
3813 if (ChangeSelectedSize (PIN_TYPE, value, r))
3814 SetChangedFlag (True);
3815 break;
3817 case F_SelectedPads:
3818 if (ChangeSelectedSize (PAD_TYPE, value, r))
3819 SetChangedFlag (True);
3820 break;
3822 case F_SelectedArcs:
3823 if (ChangeSelectedSize (ARC_TYPE, value, r))
3824 SetChangedFlag (True);
3825 break;
3827 case F_SelectedLines:
3828 if (ChangeSelectedSize (LINE_TYPE, value, r))
3829 SetChangedFlag (True);
3830 break;
3832 case F_SelectedTexts:
3833 if (ChangeSelectedSize (TEXT_TYPE, value, r))
3834 SetChangedFlag (True);
3835 break;
3837 case F_SelectedNames:
3838 if (ChangeSelectedSize (ELEMENTNAME_TYPE, value, r))
3839 SetChangedFlag (True);
3840 break;
3842 case F_SelectedElements:
3843 if (ChangeSelectedSize (ELEMENT_TYPE, value, r))
3844 SetChangedFlag (True);
3845 break;
3847 case F_Selected:
3848 case F_SelectedObjects:
3849 if (ChangeSelectedSize (CHANGESIZE_TYPES, value, r))
3850 SetChangedFlag (True);
3851 break;
3853 RestoreCrosshair (True);
3855 return 0;
3858 /* --------------------------------------------------------------------------- */
3860 static const char changedrillsize_syntax[] =
3861 "ChangeDrillSize(Object, delta)\n"
3862 "ChangeDrillSize(SelectedPins|SelectedVias|Selected|SelectedObjects, delta)";
3864 static const char changedrillsize_help[] =
3865 "Changes the drilling hole size of objects.";
3867 /* %start-doc actions ChangeDrillSize
3869 %end-doc */
3871 static int
3872 ActionChange2ndSize (int argc, char **argv, int x, int y)
3874 char *function = ARG (0);
3875 char *delta = ARG (1);
3876 char *units = ARG (2);
3877 Boolean r;
3878 float value;
3880 if (function && delta)
3882 value = GetValue (delta, units, &r);
3883 HideCrosshair (True);
3884 switch (GetFunctionID (function))
3886 case F_Object:
3888 int type;
3889 void *ptr1, *ptr2, *ptr3;
3891 gui->get_coords ("Select an Object", &x, &y);
3892 if ((type =
3893 SearchScreen (x, y, CHANGE2NDSIZE_TYPES,
3894 &ptr1, &ptr2, &ptr3)) != NO_TYPE)
3895 if (ChangeObject2ndSize
3896 (type, ptr1, ptr2, ptr3, value, r, True))
3897 SetChangedFlag (True);
3898 break;
3901 case F_SelectedVias:
3902 if (ChangeSelected2ndSize (VIA_TYPE, value, r))
3903 SetChangedFlag (True);
3904 break;
3906 case F_SelectedPins:
3907 if (ChangeSelected2ndSize (PIN_TYPE, value, r))
3908 SetChangedFlag (True);
3909 break;
3910 case F_Selected:
3911 case F_SelectedObjects:
3912 if (ChangeSelected2ndSize (PIN_TYPES, value, r))
3913 SetChangedFlag (True);
3914 break;
3916 RestoreCrosshair (True);
3918 return 0;
3921 /* --------------------------------------------------------------------------- */
3923 static const char changeclearsize_syntax[] =
3924 "ChangeClearSize(Object, delta)\n"
3925 "ChangeClearSize(SelectedPins|SelectedPads|SelectedVias, delta)\n"
3926 "ChangeClearSize(SelectedLines|SelectedArcs, delta\n"
3927 "ChangeClearSize(Selected|SelectedObjects, delta)";
3929 static const char changeclearsize_help[] =
3930 "Changes the clearance size of objects.";
3932 /* %start-doc actions ChangeClearSize
3934 If the solder mask is currently showing, this action changes the
3935 solder mask clearance. If the mask is not showing, this action
3936 changes the polygon clearance.
3938 %end-doc */
3940 static int
3941 ActionChangeClearSize (int argc, char **argv, int x, int y)
3943 char *function = ARG (0);
3944 char *delta = ARG (1);
3945 char *units = ARG (2);
3946 Boolean r;
3947 float value;
3949 if (function && delta)
3951 value = 2 * GetValue (delta, units, &r);
3952 HideCrosshair (True);
3953 switch (GetFunctionID (function))
3955 case F_Object:
3957 int type;
3958 void *ptr1, *ptr2, *ptr3;
3960 gui->get_coords ("Select and Object", &x, &y);
3961 if ((type =
3962 SearchScreen (x, y,
3963 CHANGECLEARSIZE_TYPES, &ptr1, &ptr2,
3964 &ptr3)) != NO_TYPE)
3965 if (ChangeObjectClearSize (type, ptr1, ptr2, ptr3, value, r))
3966 SetChangedFlag (True);
3967 break;
3969 case F_SelectedVias:
3970 if (ChangeSelectedClearSize (VIA_TYPE, value, r))
3971 SetChangedFlag (True);
3972 break;
3973 case F_SelectedPads:
3974 if (ChangeSelectedClearSize (PAD_TYPE, value, r))
3975 SetChangedFlag (True);
3976 break;
3977 case F_SelectedPins:
3978 if (ChangeSelectedClearSize (PIN_TYPE, value, r))
3979 SetChangedFlag (True);
3980 break;
3981 case F_SelectedLines:
3982 if (ChangeSelectedClearSize (LINE_TYPE, value, r))
3983 SetChangedFlag (True);
3984 break;
3985 case F_SelectedArcs:
3986 if (ChangeSelectedClearSize (ARC_TYPE, value, r))
3987 SetChangedFlag (True);
3988 break;
3989 case F_Selected:
3990 case F_SelectedObjects:
3991 if (ChangeSelectedClearSize (CHANGECLEARSIZE_TYPES, value, r))
3992 SetChangedFlag (True);
3993 break;
3995 RestoreCrosshair (True);
3997 return 0;
4000 /* --------------------------------------------------------------------------- */
4002 static const char minmaskgap_syntax[] =
4003 "MinMaskGap(delta)\n" "MinMaskGap(Selected, delta)";
4005 static const char minmaskgap_help[] =
4006 "Ensures the mask is a minimum distance from pins and pads.";
4008 /* %start-doc actions MinMaskGap
4010 Checks all specified pins and/or pads, and increases the mask if
4011 needed to ensure a minimum distance between the pin or pad edge and
4012 the mask edge.
4014 %end-doc */
4016 static int
4017 ActionMinMaskGap (int argc, char **argv, int x, int y)
4019 char *function = ARG (0);
4020 char *delta = ARG (1);
4021 char *units = ARG (2);
4022 Boolean r;
4023 int value;
4024 int flags;
4026 if (!function)
4027 return 1;
4028 if (strcasecmp (function, "Selected") == 0)
4029 flags = SELECTEDFLAG;
4030 else
4032 units = delta;
4033 delta = function;
4034 flags = 0;
4036 value = 2 * GetValue (delta, units, &r);
4038 HideCrosshair (True);
4039 SaveUndoSerialNumber ();
4040 ELEMENT_LOOP (PCB->Data);
4042 PIN_LOOP (element);
4044 if (!TEST_FLAGS (flags, pin))
4045 continue;
4046 if (pin->Mask < pin->Thickness + value)
4048 ChangeObjectMaskSize (PIN_TYPE, element, pin, 0,
4049 pin->Thickness + value, 1);
4050 RestoreUndoSerialNumber ();
4053 END_LOOP;
4054 PAD_LOOP (element);
4056 if (!TEST_FLAGS (flags, pad))
4057 continue;
4058 if (pad->Mask < pad->Thickness + value)
4060 ChangeObjectMaskSize (PAD_TYPE, element, pad, 0,
4061 pad->Thickness + value, 1);
4062 RestoreUndoSerialNumber ();
4065 END_LOOP;
4067 END_LOOP;
4068 VIA_LOOP (PCB->Data);
4070 if (!TEST_FLAGS (flags, via))
4071 continue;
4072 if (via->Mask && via->Mask < via->Thickness + value)
4074 ChangeObjectMaskSize (VIA_TYPE, via, 0, 0, via->Thickness + value, 1);
4075 RestoreUndoSerialNumber ();
4078 END_LOOP;
4079 RestoreUndoSerialNumber ();
4080 IncrementUndoSerialNumber ();
4081 return 0;
4084 /* --------------------------------------------------------------------------- */
4086 static const char changepinname_syntax[] =
4087 "ChangePinName(ElementName,PinNumber,PinName)";
4089 static const char changepinname_help[] =
4090 "Sets the name of a specific pin on a specific element.";
4092 /* %start-doc actions ChangePinName
4094 This can be especially useful for annotating pin names from a
4095 schematic to the layout without requiring knowledge of the pcb file
4096 format.
4098 @example
4099 ChangePinName(U3, 7, VCC)
4100 @end example
4102 %end-doc */
4104 static int
4105 ActionChangePinName (int argc, char **argv, int x, int y)
4107 int changed = 0;
4108 char *refdes, *pinnum, *pinname;
4110 if (argc != 3)
4112 AFAIL (changepinname);
4115 refdes = argv[0];
4116 pinnum = argv[1];
4117 pinname = argv[2];
4119 ELEMENT_LOOP (PCB->Data);
4121 if (NSTRCMP (refdes, NAMEONPCB_NAME (element)) == 0)
4123 PIN_LOOP (element);
4125 if (NSTRCMP (pinnum, pin->Number) == 0)
4127 AddObjectToChangeNameUndoList (PIN_TYPE, NULL, NULL,
4128 pin, pin->Name);
4130 * Note: we can't free() pin->Name first because
4131 * it is used in the undo list
4133 pin->Name = strdup (pinname);
4134 SetChangedFlag (True);
4135 changed = 1;
4138 END_LOOP;
4140 PAD_LOOP (element);
4142 if (NSTRCMP (pinnum, pad->Number) == 0)
4144 AddObjectToChangeNameUndoList (PAD_TYPE, NULL, NULL,
4145 pad, pad->Name);
4147 * Note: we can't free() pad->Name first because
4148 * it is used in the undo list
4150 pad->Name = strdup (pinname);
4151 SetChangedFlag (True);
4152 changed = 1;
4155 END_LOOP;
4158 END_LOOP;
4160 * done with our action so increment the undo # if we actually
4161 * changed anything
4163 if (changed)
4165 IncrementUndoSerialNumber ();
4166 gui->invalidate_all ();
4169 return 0;
4172 /* --------------------------------------------------------------------------- */
4174 static const char changename_syntax[] =
4175 "ChangeName(Object)\n" "ChangeName(Layout|Layer)";
4177 static const char changename_help[] = "Sets the name of objects.";
4179 /* %start-doc actions ChangeName
4181 @table @code
4183 @item Object
4184 Changes the name of the element under the cursor.
4186 @item Layout
4187 Changes the name of the layout. This is printed on the fab drawings.
4189 @item Layer
4190 Changes the name of the currently active layer.
4192 @end table
4194 %end-doc */
4197 ActionChangeName (int argc, char **argv, int x, int y)
4199 char *function = ARG (0);
4200 char *name;
4202 if (function)
4204 HideCrosshair (True);
4205 switch (GetFunctionID (function))
4207 /* change the name of an object */
4208 case F_Object:
4210 int type;
4211 void *ptr1, *ptr2, *ptr3;
4213 gui->get_coords ("Select an Object", &x, &y);
4214 if ((type =
4215 SearchScreen (x, y, CHANGENAME_TYPES,
4216 &ptr1, &ptr2, &ptr3)) != NO_TYPE)
4218 SaveUndoSerialNumber ();
4219 if (QueryInputAndChangeObjectName (type, ptr1, ptr2, ptr3))
4221 SetChangedFlag (True);
4222 if (type == ELEMENT_TYPE)
4224 RubberbandTypePtr ptr;
4225 int i;
4227 RestoreUndoSerialNumber ();
4228 Crosshair.AttachedObject.RubberbandN = 0;
4229 LookupRatLines (type, ptr1, ptr2, ptr3);
4230 ptr = Crosshair.AttachedObject.Rubberband;
4231 for (i = 0; i < Crosshair.AttachedObject.RubberbandN;
4232 i++, ptr++)
4234 if (PCB->RatOn)
4235 EraseRat ((RatTypePtr) ptr->Line);
4236 MoveObjectToRemoveUndoList (RATLINE_TYPE,
4237 ptr->Line, ptr->Line,
4238 ptr->Line);
4240 IncrementUndoSerialNumber ();
4241 Draw ();
4245 break;
4248 /* change the layout's name */
4249 case F_Layout:
4250 name =
4251 gui->prompt_for (_("Enter the layout name:"), EMPTY (PCB->Name));
4252 if (name && ChangeLayoutName (name)) /* XXX memory leak */
4253 SetChangedFlag (True);
4254 break;
4256 /* change the name of the active layer */
4257 case F_Layer:
4258 name = gui->prompt_for (_("Enter the layer name:"),
4259 EMPTY (CURRENT->Name));
4260 if (name && ChangeLayerName (CURRENT, name)) /* XXX memory leak */
4261 SetChangedFlag (True);
4262 break;
4264 RestoreCrosshair (True);
4266 return 0;
4270 /* --------------------------------------------------------------------------- */
4272 static const char morphpolygon_syntax[] = "MorphPolygon(Object|Selected)";
4274 static const char morphpolygon_help[] =
4275 "Converts dead polygon islands into separate polygons.";
4277 /* %start-doc actions MorphPolygon
4279 If a polygon is divided into unconnected "islands", you can use
4280 this command to convert the otherwise disappeared islands into
4281 separate polygons. Be sure the cursor is over a portion of the
4282 polygon that remains visible. Very small islands that may flake
4283 off are automatically deleted.
4285 %end-doc */
4287 static int
4288 ActionMorphPolygon (int argc, char **argv, int x, int y)
4290 char *function = ARG (0);
4291 if (function)
4293 HideCrosshair (True);
4294 switch (GetFunctionID (function))
4296 case F_Object:
4298 int type;
4299 void *ptr1, *ptr2, *ptr3;
4301 gui->get_coords ("Select an Object", &x, &y);
4302 if ((type = SearchScreen (x, y, POLYGON_TYPE,
4303 &ptr1, &ptr2, &ptr3)) != NO_TYPE)
4305 MorphPolygon ((LayerType *) ptr1, (PolygonType *) ptr3);
4306 Draw ();
4307 IncrementUndoSerialNumber ();
4309 break;
4311 case F_Selected:
4312 case F_SelectedObjects:
4313 ALLPOLYGON_LOOP (PCB->Data);
4315 if (TEST_FLAG (SELECTEDFLAG, polygon))
4316 MorphPolygon (layer, polygon);
4318 ENDALL_LOOP;
4319 Draw ();
4320 IncrementUndoSerialNumber ();
4321 break;
4324 return 0;
4327 /* --------------------------------------------------------------------------- */
4329 static const char togglehidename_syntax[] =
4330 "ToggleHideName(Object|SelectedElements)";
4332 static const char togglehidename_help[] =
4333 "Toggles the visibility of element names.";
4335 /* %start-doc actions ToggleHideName
4337 If names are hidden you won't see them on the screen and they will not
4338 appear on the silk layer when you print the layout.
4340 %end-doc */
4342 static int
4343 ActionToggleHideName (int argc, char **argv, int x, int y)
4345 char *function = ARG (0);
4346 if (function && PCB->ElementOn)
4348 HideCrosshair (True);
4349 switch (GetFunctionID (function))
4351 case F_Object:
4353 int type;
4354 void *ptr1, *ptr2, *ptr3;
4356 gui->get_coords ("Select an Object", &x, &y);
4357 if ((type = SearchScreen (x, y, ELEMENT_TYPE,
4358 &ptr1, &ptr2, &ptr3)) != NO_TYPE)
4360 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr3);
4361 EraseElementName ((ElementTypePtr) ptr2);
4362 TOGGLE_FLAG (HIDENAMEFLAG, (ElementTypePtr) ptr2);
4363 DrawElementName ((ElementTypePtr) ptr2, 0);
4364 Draw ();
4365 IncrementUndoSerialNumber ();
4367 break;
4369 case F_SelectedElements:
4370 case F_Selected:
4372 Boolean changed = False;
4373 ELEMENT_LOOP (PCB->Data);
4375 if ((TEST_FLAG (SELECTEDFLAG, element) ||
4376 TEST_FLAG (SELECTEDFLAG,
4377 &NAMEONPCB_TEXT (element)))
4378 && (FRONT (element) || PCB->InvisibleObjectsOn))
4380 AddObjectToFlagUndoList (ELEMENT_TYPE, element,
4381 element, element);
4382 EraseElementName (element);
4383 TOGGLE_FLAG (HIDENAMEFLAG, element);
4384 DrawElementName (element, 0);
4385 changed = True;
4388 END_LOOP;
4389 if (changed)
4391 Draw ();
4392 IncrementUndoSerialNumber ();
4396 RestoreCrosshair (True);
4398 return 0;
4401 /* --------------------------------------------------------------------------- */
4403 static const char changejoin_syntax[] =
4404 "ChangeJoin(ToggleObject|SelectedLines|SelectedArcs|Selected)";
4406 static const char changejoin_help[] =
4407 "Changes the join (clearance through polygons) of objects.";
4409 /* %start-doc actions ChangeJoin
4411 The join flag determines whether a line or arc, drawn to intersect a
4412 polygon, electrically connects to the polygon or not. When joined,
4413 the line/arc is simply drawn over the polygon, making an electrical
4414 connection. When not joined, a gap is drawn between the line and the
4415 polygon, insulating them from each other.
4417 %end-doc */
4419 static int
4420 ActionChangeJoin (int argc, char **argv, int x, int y)
4422 char *function = ARG (0);
4423 if (function)
4425 HideCrosshair (True);
4426 switch (GetFunctionID (function))
4428 case F_ToggleObject:
4429 case F_Object:
4431 int type;
4432 void *ptr1, *ptr2, *ptr3;
4434 gui->get_coords ("Select an Object", &x, &y);
4435 if ((type =
4436 SearchScreen (x, y, CHANGEJOIN_TYPES,
4437 &ptr1, &ptr2, &ptr3)) != NO_TYPE)
4438 if (ChangeObjectJoin (type, ptr1, ptr2, ptr3))
4439 SetChangedFlag (True);
4440 break;
4443 case F_SelectedLines:
4444 if (ChangeSelectedJoin (LINE_TYPE))
4445 SetChangedFlag (True);
4446 break;
4448 case F_SelectedArcs:
4449 if (ChangeSelectedJoin (ARC_TYPE))
4450 SetChangedFlag (True);
4451 break;
4453 case F_Selected:
4454 case F_SelectedObjects:
4455 if (ChangeSelectedJoin (CHANGEJOIN_TYPES))
4456 SetChangedFlag (True);
4457 break;
4459 RestoreCrosshair (True);
4461 return 0;
4464 /* --------------------------------------------------------------------------- */
4466 static const char changesquare_syntax[] =
4467 "ChangeSquare(ToggleObject)\n"
4468 "ChangeSquare(SelectedElements|SelectedPins)\n"
4469 "ChangeSquare(Selected|SelectedObjects)";
4471 static const char changesquare_help[] =
4472 "Changes the square flag of pins and pads.";
4474 /* %start-doc actions ChangeSquare
4476 Note that @code{Pins} means both pins and pads.
4478 @pinshapes
4480 %end-doc */
4482 static int
4483 ActionChangeSquare (int argc, char **argv, int x, int y)
4485 char *function = ARG (0);
4486 if (function)
4488 HideCrosshair (True);
4489 switch (GetFunctionID (function))
4491 case F_ToggleObject:
4492 case F_Object:
4494 int type;
4495 void *ptr1, *ptr2, *ptr3;
4497 gui->get_coords ("Select an Object", &x, &y);
4498 if ((type =
4499 SearchScreen (x, y, CHANGESQUARE_TYPES,
4500 &ptr1, &ptr2, &ptr3)) != NO_TYPE)
4501 if (ChangeObjectSquare (type, ptr1, ptr2, ptr3))
4502 SetChangedFlag (True);
4503 break;
4506 case F_SelectedElements:
4507 if (ChangeSelectedSquare (ELEMENT_TYPE))
4508 SetChangedFlag (True);
4509 break;
4511 case F_SelectedPins:
4512 if (ChangeSelectedSquare (PIN_TYPE | PAD_TYPE))
4513 SetChangedFlag (True);
4514 break;
4516 case F_Selected:
4517 case F_SelectedObjects:
4518 if (ChangeSelectedSquare (PIN_TYPE | PAD_TYPE))
4519 SetChangedFlag (True);
4520 break;
4522 RestoreCrosshair (True);
4524 return 0;
4527 /* --------------------------------------------------------------------------- */
4529 static const char setsquare_syntax[] =
4530 "SetSquare(ToggleObject|SelectedElements|SelectedPins)";
4532 static const char setsquare_help[] = "sets the square-flag of objects.";
4534 /* %start-doc actions SetSquare
4536 Note that @code{Pins} means pins and pads.
4538 @pinshapes
4540 %end-doc */
4542 static int
4543 ActionSetSquare (int argc, char **argv, int x, int y)
4545 char *function = ARG (0);
4546 if (function && *function)
4548 /* HideCrosshair (True); */
4549 switch (GetFunctionID (function))
4551 case F_ToggleObject:
4552 case F_Object:
4554 int type;
4555 void *ptr1, *ptr2, *ptr3;
4557 gui->get_coords ("Select an object", &x, &y);
4558 if ((type =
4559 SearchScreen (x, y, CHANGESQUARE_TYPES,
4560 &ptr1, &ptr2, &ptr3)) != NO_TYPE)
4561 if (SetObjectSquare (type, ptr1, ptr2, ptr3))
4562 SetChangedFlag (True);
4563 break;
4566 case F_SelectedElements:
4567 if (SetSelectedSquare (ELEMENT_TYPE))
4568 SetChangedFlag (True);
4569 break;
4571 case F_SelectedPins:
4572 if (SetSelectedSquare (PIN_TYPE | PAD_TYPE))
4573 SetChangedFlag (True);
4574 break;
4576 case F_Selected:
4577 case F_SelectedObjects:
4578 if (SetSelectedSquare (PIN_TYPE | PAD_TYPE))
4579 SetChangedFlag (True);
4580 break;
4582 /* RestoreCrosshair (True); */
4584 return 0;
4587 /* --------------------------------------------------------------------------- */
4589 static const char clearsquare_syntax[] =
4590 "ClearSquare(ToggleObject|SelectedElements|SelectedPins)";
4592 static const char clearsquare_help[] =
4593 "Clears the square-flag of pins and pads.";
4595 /* %start-doc actions ClearSquare
4597 Note that @code{Pins} means pins and pads.
4599 @pinshapes
4601 %end-doc */
4603 static int
4604 ActionClearSquare (int argc, char **argv, int x, int y)
4606 char *function = ARG (0);
4607 if (function && *function)
4609 /* HideCrosshair (True); */
4610 switch (GetFunctionID (function))
4612 case F_ToggleObject:
4613 case F_Object:
4615 int type;
4616 void *ptr1, *ptr2, *ptr3;
4618 gui->get_coords ("Select an Object", &x, &y);
4619 if ((type =
4620 SearchScreen (x, y, CHANGESQUARE_TYPES,
4621 &ptr1, &ptr2, &ptr3)) != NO_TYPE)
4622 if (ClrObjectSquare (type, ptr1, ptr2, ptr3))
4623 SetChangedFlag (True);
4624 break;
4627 case F_SelectedElements:
4628 if (ClrSelectedSquare (ELEMENT_TYPE))
4629 SetChangedFlag (True);
4630 break;
4632 case F_SelectedPins:
4633 if (ClrSelectedSquare (PIN_TYPE | PAD_TYPE))
4634 SetChangedFlag (True);
4635 break;
4637 case F_Selected:
4638 case F_SelectedObjects:
4639 if (ClrSelectedSquare (PIN_TYPE | PAD_TYPE))
4640 SetChangedFlag (True);
4641 break;
4643 /* RestoreCrosshair (True); */
4645 return 0;
4648 /* --------------------------------------------------------------------------- */
4650 static const char changeoctagon_syntax[] =
4651 "ChangeOctagon(Object|ToggleObject|SelectedObjects|Selected)\n"
4652 "ChangeOctagon(SelectedElements|SelectedPins|SelectedVias)";
4654 static const char changeoctagon_help[] =
4655 "Changes the octagon-flag of pins and vias.";
4657 /* %start-doc actions ChangeOctagon
4659 @pinshapes
4661 %end-doc */
4663 static int
4664 ActionChangeOctagon (int argc, char **argv, int x, int y)
4666 char *function = ARG (0);
4667 if (function)
4669 /* HideCrosshair (True); */
4670 switch (GetFunctionID (function))
4672 case F_ToggleObject:
4673 case F_Object:
4675 int type;
4676 void *ptr1, *ptr2, *ptr3;
4678 gui->get_coords ("Select an Object", &x, &y);
4679 if ((type =
4680 SearchScreen (x, y, CHANGEOCTAGON_TYPES,
4681 &ptr1, &ptr2, &ptr3)) != NO_TYPE)
4682 if (ChangeObjectOctagon (type, ptr1, ptr2, ptr3))
4683 SetChangedFlag (True);
4684 break;
4687 case F_SelectedElements:
4688 if (ChangeSelectedOctagon (ELEMENT_TYPE))
4689 SetChangedFlag (True);
4690 break;
4692 case F_SelectedPins:
4693 if (ChangeSelectedOctagon (PIN_TYPE))
4694 SetChangedFlag (True);
4695 break;
4697 case F_SelectedVias:
4698 if (ChangeSelectedOctagon (VIA_TYPE))
4699 SetChangedFlag (True);
4700 break;
4702 case F_Selected:
4703 case F_SelectedObjects:
4704 if (ChangeSelectedOctagon (PIN_TYPES))
4705 SetChangedFlag (True);
4706 break;
4708 /* RestoreCrosshair (True); */
4710 return 0;
4713 /* --------------------------------------------------------------------------- */
4715 static const char setoctagon_syntax[] =
4716 "SetOctagon(Object|ToggleObject|SelectedElements|Selected)";
4718 static const char setoctagon_help[] = "Sets the octagon-flag of objects.";
4720 /* %start-doc actions SetOctagon
4722 @pinshapes
4724 %end-doc */
4726 static int
4727 ActionSetOctagon (int argc, char **argv, int x, int y)
4729 char *function = ARG (0);
4730 if (function)
4732 /* HideCrosshair (True); */
4733 switch (GetFunctionID (function))
4735 case F_ToggleObject:
4736 case F_Object:
4738 int type;
4739 void *ptr1, *ptr2, *ptr3;
4741 gui->get_coords ("Select an object", &x, &y);
4742 if ((type =
4743 SearchScreen (x, y, CHANGEOCTAGON_TYPES,
4744 &ptr1, &ptr2, &ptr3)) != NO_TYPE)
4745 if (SetObjectOctagon (type, ptr1, ptr2, ptr3))
4746 SetChangedFlag (True);
4747 break;
4750 case F_SelectedElements:
4751 if (SetSelectedOctagon (ELEMENT_TYPE))
4752 SetChangedFlag (True);
4753 break;
4755 case F_SelectedPins:
4756 if (SetSelectedOctagon (PIN_TYPE))
4757 SetChangedFlag (True);
4758 break;
4760 case F_SelectedVias:
4761 if (SetSelectedOctagon (VIA_TYPE))
4762 SetChangedFlag (True);
4763 break;
4765 case F_Selected:
4766 case F_SelectedObjects:
4767 if (SetSelectedOctagon (PIN_TYPES))
4768 SetChangedFlag (True);
4769 break;
4771 /* RestoreCrosshair (True); */
4773 return 0;
4776 /* --------------------------------------------------------------------------- */
4778 static const char clearoctagon_syntax[] =
4779 "ClearOctagon(ToggleObject|Object|SelectedObjects|Selected)\n"
4780 "ClearOctagon(SelectedElements|SelectedPins|SelectedVias)";
4782 static const char clearoctagon_help[] =
4783 "Clears the octagon-flag of pins and vias.";
4785 /* %start-doc actions ClearOctagon
4787 @pinshapes
4789 %end-doc */
4791 static int
4792 ActionClearOctagon (int argc, char **argv, int x, int y)
4794 char *function = ARG (0);
4795 if (function)
4797 /* HideCrosshair (True); */
4798 switch (GetFunctionID (function))
4800 case F_ToggleObject:
4801 case F_Object:
4803 int type;
4804 void *ptr1, *ptr2, *ptr3;
4806 gui->get_coords ("Select an Object", &x, &y);
4807 if ((type =
4808 SearchScreen (Crosshair.X, Crosshair.Y, CHANGEOCTAGON_TYPES,
4809 &ptr1, &ptr2, &ptr3)) != NO_TYPE)
4810 if (ClrObjectOctagon (type, ptr1, ptr2, ptr3))
4811 SetChangedFlag (True);
4812 break;
4815 case F_SelectedElements:
4816 if (ClrSelectedOctagon (ELEMENT_TYPE))
4817 SetChangedFlag (True);
4818 break;
4820 case F_SelectedPins:
4821 if (ClrSelectedOctagon (PIN_TYPE))
4822 SetChangedFlag (True);
4823 break;
4825 case F_SelectedVias:
4826 if (ClrSelectedOctagon (VIA_TYPE))
4827 SetChangedFlag (True);
4828 break;
4830 case F_Selected:
4831 case F_SelectedObjects:
4832 if (ClrSelectedOctagon (PIN_TYPES))
4833 SetChangedFlag (True);
4834 break;
4836 /* RestoreCrosshair (True); */
4838 return 0;
4841 /* --------------------------------------------------------------------------- */
4843 static const char changehold_syntax[] =
4844 "ChangeHole(ToggleObject|Object|SelectedVias|Selected)";
4846 static const char changehold_help[] = "Changes the hole flag of objects.";
4848 /* %start-doc actions ChangeHole
4850 The "hole flag" of a via determines whether the via is a
4851 plated-through hole (not set), or an unplated hole (set).
4853 %end-doc */
4855 static int
4856 ActionChangeHole (int argc, char **argv, int x, int y)
4858 char *function = ARG (0);
4859 if (function)
4861 /* HideCrosshair (True); */
4862 switch (GetFunctionID (function))
4864 case F_ToggleObject:
4865 case F_Object:
4867 int type;
4868 void *ptr1, *ptr2, *ptr3;
4870 gui->get_coords ("Select an Object", &x, &y);
4871 if ((type = SearchScreen (x, y, VIA_TYPE,
4872 &ptr1, &ptr2, &ptr3)) != NO_TYPE
4873 && ChangeHole ((PinTypePtr) ptr3))
4874 IncrementUndoSerialNumber ();
4875 break;
4878 case F_SelectedVias:
4879 case F_Selected:
4880 if (ChangeSelectedHole ())
4881 SetChangedFlag (True);
4882 break;
4884 /* RestoreCrosshair (True); */
4886 return 0;
4889 /* --------------------------------------------------------------------------- */
4891 static const char changepaste_syntax[] =
4892 "ChangePaste(ToggleObject|Object|SelectedPads|Selected)";
4894 static const char changepaste_help[] = "Changes the no paste flag of objects.";
4896 /* %start-doc actions ChangePaste
4898 The "no paste flag" of a pad determines whether the solderpaste
4899 stencil will have an opening for the pad (no set) or if there wil be
4900 no solderpaste on the pad (set). This is used for things such as
4901 fiducial pads.
4903 %end-doc */
4905 static int
4906 ActionChangePaste (int argc, char **argv, int x, int y)
4908 char *function = ARG (0);
4909 if (function)
4911 /* HideCrosshair (True); */
4912 switch (GetFunctionID (function))
4914 case F_ToggleObject:
4915 case F_Object:
4917 int type;
4918 void *ptr1, *ptr2, *ptr3;
4920 gui->get_coords ("Select an Object", &x, &y);
4921 if ((type = SearchScreen (x, y, PAD_TYPE,
4922 &ptr1, &ptr2, &ptr3)) != NO_TYPE
4923 && ChangePaste ((PadTypePtr) ptr3))
4924 IncrementUndoSerialNumber ();
4925 break;
4928 case F_SelectedPads:
4929 case F_Selected:
4930 if (ChangeSelectedPaste ())
4931 SetChangedFlag (True);
4932 break;
4934 /* RestoreCrosshair (True); */
4936 return 0;
4939 /* --------------------------------------------------------------------------- */
4941 static const char select_syntax[] =
4942 "Select(ToggleObject)\n"
4943 "Select(All|Block|Connection)\n"
4944 "Select(ElementByName|ObjectByName|PadByName|PinByName)\n"
4945 "Select(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
4946 "Select(TextByName|ViaByName)\n"
4947 "Select(TextByName|ViaByName, Name)\n" "Select(Convert)";
4949 static const char select_help[] = "Toggles or sets the selection";
4951 /* %start-doc actions Select
4953 @table @code
4955 @item ElementByName
4956 @item ObjectByName
4957 @item PadByName
4958 @item PinByName
4959 @item TextByName
4960 @item ViaByName
4962 These all rely on having a regular expression parser built into
4963 @code{pcb}. If the name is not specified then the user is prompted
4964 for a pattern, and all objects that match the pattern and are of the
4965 type specified are selected.
4967 @item Object
4968 @item ToggleObject
4969 Selects the object under the cursor.
4971 @item Block
4972 Selects all objects in a rectangle indicated by the cursor.
4974 @item All
4975 Selects all objects on the board.
4977 @item Connection
4978 Selects all connections with the ``found'' flag set.
4980 @item Convert
4981 Converts the selected objects to an element. This uses the highest
4982 numbered paste buffer.
4984 @end table
4986 %end-doc */
4988 static int
4989 ActionSelect (int argc, char **argv, int x, int y)
4991 char *function = ARG (0);
4992 if (function)
4995 HideCrosshair (True);
4996 switch (GetFunctionID (function))
4998 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
4999 int type;
5000 /* select objects by their names */
5001 case F_ElementByName:
5002 type = ELEMENT_TYPE;
5003 goto commonByName;
5004 case F_ObjectByName:
5005 type = ALL_TYPES;
5006 goto commonByName;
5007 case F_PadByName:
5008 type = PAD_TYPE;
5009 goto commonByName;
5010 case F_PinByName:
5011 type = PIN_TYPE;
5012 goto commonByName;
5013 case F_TextByName:
5014 type = TEXT_TYPE;
5015 goto commonByName;
5016 case F_ViaByName:
5017 type = VIA_TYPE;
5018 goto commonByName;
5020 commonByName:
5022 char *pattern = ARG (1);
5024 if (pattern
5025 || (pattern =
5026 gui->prompt_for (_("Enter pattern:"), "")) != NULL)
5028 if (SelectObjectByName (type, pattern, True))
5029 SetChangedFlag (True);
5030 if (ARG (1) == 0)
5031 free (pattern);
5033 break;
5035 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5037 /* select a single object */
5038 case F_ToggleObject:
5039 case F_Object:
5040 if (SelectObject ())
5041 SetChangedFlag (True);
5042 break;
5044 /* all objects in block */
5045 case F_Block:
5047 BoxType box;
5049 box.X1 = MIN (Crosshair.AttachedBox.Point1.X,
5050 Crosshair.AttachedBox.Point2.X);
5051 box.Y1 = MIN (Crosshair.AttachedBox.Point1.Y,
5052 Crosshair.AttachedBox.Point2.Y);
5053 box.X2 = MAX (Crosshair.AttachedBox.Point1.X,
5054 Crosshair.AttachedBox.Point2.X);
5055 box.Y2 = MAX (Crosshair.AttachedBox.Point1.Y,
5056 Crosshair.AttachedBox.Point2.Y);
5057 NotifyBlock ();
5058 if (Crosshair.AttachedBox.State == STATE_THIRD &&
5059 SelectBlock (&box, True))
5061 SetChangedFlag (True);
5062 Crosshair.AttachedBox.State = STATE_FIRST;
5064 break;
5067 /* select all visible objects */
5068 case F_All:
5070 BoxType box;
5072 box.X1 = -MAX_COORD;
5073 box.Y1 = -MAX_COORD;
5074 box.X2 = MAX_COORD;
5075 box.Y2 = MAX_COORD;
5076 if (SelectBlock (&box, True))
5077 SetChangedFlag (True);
5078 break;
5081 /* all found connections */
5082 case F_Connection:
5083 if (SelectConnection (True))
5085 IncrementUndoSerialNumber ();
5086 SetChangedFlag (True);
5088 break;
5090 case F_Convert:
5092 int x, y;
5093 Note.Buffer = Settings.BufferNumber;
5094 SetBufferNumber (MAX_BUFFER - 1);
5095 ClearBuffer (PASTEBUFFER);
5096 gui->get_coords ("Select the Element's Mark Location", &x, &y);
5097 x = GRIDFIT_X (x, PCB->Grid);
5098 y = GRIDFIT_Y (y, PCB->Grid);
5099 AddSelectedToBuffer (PASTEBUFFER, x, y, True);
5100 SaveUndoSerialNumber ();
5101 RemoveSelected ();
5102 ConvertBufferToElement (PASTEBUFFER);
5103 RestoreUndoSerialNumber ();
5104 CopyPastebufferToLayout (x, y);
5105 SetBufferNumber (Note.Buffer);
5107 break;
5109 default:
5110 RestoreCrosshair (True);
5111 AFAIL (select);
5112 break;
5114 RestoreCrosshair (True);
5116 return 0;
5119 /* FLAG(have_regex,FlagHaveRegex,0) */
5121 FlagHaveRegex (int parm)
5123 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5124 return 1;
5125 #else
5126 return 0;
5127 #endif
5130 /* --------------------------------------------------------------------------- */
5132 static const char unselect_syntax[] =
5133 "Unselect(All|Block|Connection)\n"
5134 "Unselect(ElementByName|ObjectByName|PadByName|PinByName)\n"
5135 "Unselect(ElementByName|ObjectByName|PadByName|PinByName, Name)\n"
5136 "Unselect(TextByName|ViaByName)\n" "Unselect(TextByName|ViaByName, Name)\n";
5138 static const char unselect_help[] =
5139 "unselects the object at the pointer location or the specified objects";
5141 /* %start-doc actions Unselect
5143 @table @code
5145 @item All
5146 Unselect all objects.
5148 @item Block
5149 Unselect all objects in a rectangle given by the cursor.
5151 @item Connection
5152 Unselect all connections with the ``found'' flag set.
5154 @item ElementByName
5155 @item ObjectByName
5156 @item PadByName
5157 @item PinByName
5158 @item TextByName
5159 @item ViaByName
5161 These all rely on having a regular expression parser built into
5162 @code{pcb}. If the name is not specified then the user is prompted
5163 for a pattern, and all objects that match the pattern and are of the
5164 type specified are unselected.
5167 @end table
5169 %end-doc */
5171 static int
5172 ActionUnselect (int argc, char **argv, int x, int y)
5174 char *function = ARG (0);
5176 if (function)
5178 HideCrosshair (True);
5179 switch (GetFunctionID (function))
5181 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
5182 int type;
5183 /* select objects by their names */
5184 case F_ElementByName:
5185 type = ELEMENT_TYPE;
5186 goto commonByName;
5187 case F_ObjectByName:
5188 type = ALL_TYPES;
5189 goto commonByName;
5190 case F_PadByName:
5191 type = PAD_TYPE;
5192 goto commonByName;
5193 case F_PinByName:
5194 type = PIN_TYPE;
5195 goto commonByName;
5196 case F_TextByName:
5197 type = TEXT_TYPE;
5198 goto commonByName;
5199 case F_ViaByName:
5200 type = VIA_TYPE;
5201 goto commonByName;
5203 commonByName:
5205 char *pattern = ARG (1);
5207 if (pattern
5208 || (pattern =
5209 gui->prompt_for (_("Enter pattern:"), "")) != NULL)
5211 if (SelectObjectByName (type, pattern, False))
5212 SetChangedFlag (True);
5213 if (ARG (1) == 0)
5214 free (pattern);
5216 break;
5218 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
5220 /* all objects in block */
5221 case F_Block:
5223 BoxType box;
5225 box.X1 = MIN (Crosshair.AttachedBox.Point1.X,
5226 Crosshair.AttachedBox.Point2.X);
5227 box.Y1 = MIN (Crosshair.AttachedBox.Point1.Y,
5228 Crosshair.AttachedBox.Point2.Y);
5229 box.X2 = MAX (Crosshair.AttachedBox.Point1.X,
5230 Crosshair.AttachedBox.Point2.X);
5231 box.Y2 = MAX (Crosshair.AttachedBox.Point1.Y,
5232 Crosshair.AttachedBox.Point2.Y);
5233 NotifyBlock ();
5234 if (Crosshair.AttachedBox.State == STATE_THIRD &&
5235 SelectBlock (&box, False))
5237 SetChangedFlag (True);
5238 Crosshair.AttachedBox.State = STATE_FIRST;
5240 break;
5243 /* unselect all visible objects */
5244 case F_All:
5246 BoxType box;
5248 box.X1 = -MAX_COORD;
5249 box.Y1 = -MAX_COORD;
5250 box.X2 = MAX_COORD;
5251 box.Y2 = MAX_COORD;
5252 if (SelectBlock (&box, False))
5253 SetChangedFlag (True);
5254 break;
5257 /* all found connections */
5258 case F_Connection:
5259 if (SelectConnection (False))
5261 IncrementUndoSerialNumber ();
5262 SetChangedFlag (True);
5264 break;
5266 default:
5267 RestoreCrosshair (True);
5268 AFAIL (unselect);
5269 break;
5272 RestoreCrosshair (True);
5274 return 0;
5277 /* --------------------------------------------------------------------------- */
5279 static const char saveto_syntax[] =
5280 "SaveTo(Layout|LayoutAs,filename)\n"
5281 "SaveTo(AllConnections|AllUnusedPins|ElementConnections,filename)";
5283 static const char saveto_help[] = "Saves data to a file.";
5285 /* %start-doc actions SaveTo
5287 @table @code
5289 @item Layout
5290 Saves the current layout.
5292 @item LayoutAs
5293 Saves the current layout, and remembers the filename used.
5295 @item AllConnections
5296 Save all connections to a file.
5298 @item AllUnusedPins
5299 List all unused pins to a file.
5301 @item ElementConnections
5302 Save connections to the element at the cursor to a file.
5304 @end table
5306 %end-doc */
5308 static int
5309 ActionSaveTo (int argc, char **argv, int x, int y)
5311 char *function;
5312 char *name;
5314 function = argv[0];
5315 name = argv[1];
5316 if (argc != 2)
5317 AFAIL (saveto);
5319 if (strcasecmp (function, "LayoutAs") == 0)
5321 MYFREE (PCB->Filename);
5322 PCB->Filename = MyStrdup (name, __FUNCTION__);
5323 function = "Layout";
5325 if (strcasecmp (function, "Layout") == 0)
5327 SavePCB (PCB->Filename);
5328 return 0;
5331 if (strcasecmp (function, "AllConnections") == 0)
5333 FILE *fp;
5334 Boolean result;
5335 if ((fp = CheckAndOpenFile (name, True, False, &result, NULL)) != NULL)
5337 LookupConnectionsToAllElements (fp);
5338 fclose (fp);
5339 SetChangedFlag (True);
5341 return 0;
5344 if (strcasecmp (function, "AllUnusedPins") == 0)
5346 FILE *fp;
5347 Boolean result;
5348 if ((fp = CheckAndOpenFile (name, True, False, &result, NULL)) != NULL)
5350 LookupUnusedPins (fp);
5351 fclose (fp);
5352 SetChangedFlag (True);
5354 return 0;
5357 if (strcasecmp (function, "ElementConnections") == 0)
5359 ElementTypePtr element;
5360 void *ptrtmp;
5361 FILE *fp;
5362 Boolean result;
5364 if ((SearchScreen (Crosshair.X, Crosshair.Y, ELEMENT_TYPE,
5365 &ptrtmp, &ptrtmp, &ptrtmp)) != NO_TYPE)
5367 element = (ElementTypePtr) ptrtmp;
5368 if ((fp =
5369 CheckAndOpenFile (name, True, False, &result, NULL)) != NULL)
5371 LookupElementConnections (element, fp);
5372 fclose (fp);
5373 SetChangedFlag (True);
5376 return 0;
5379 AFAIL (saveto);
5382 /* --------------------------------------------------------------------------- */
5384 static const char savesettings_syntax[] =
5385 "SaveSettings()\n" "SaveSettings(local)";
5387 static const char savesettings_help[] = "Saves settings.";
5389 /* %start-doc actions SaveSettings
5391 If you pass no arguments, the settings are stored in
5392 @code{$HOME/.pcb/settings}. If you pass the word @code{local} they're
5393 saved in @code{./pcb.settings}.
5395 %end-doc */
5397 static int
5398 ActionSaveSettings (int argc, char **argv, int x, int y)
5400 int locally = argc > 0 ? (strncasecmp (argv[0], "local", 5) == 0) : 0;
5401 hid_save_settings (locally);
5402 return 0;
5405 /* --------------------------------------------------------------------------- */
5407 static const char loadfrom_syntax[] =
5408 "LoadFrom(Layout|LayoutToBuffer|ElementToBuffer|Netlist|Revert,filename)";
5410 static const char loadfrom_help[] = "Load layout data from a file.";
5412 /* %start-doc actions LoadFrom
5414 This action assumes you know what the filename is. The various GUIs
5415 should have a similar @code{Load} action where the filename is
5416 optional, and will provide their own file selection mechanism to let
5417 you choose the file name.
5419 @table @code
5421 @item Layout
5422 Loads an entire PCB layout, replacing the current one.
5424 @item LayoutToBuffer
5425 Loads an entire PCB layout to the paste buffer.
5427 @item ElementToBuffer
5428 Loads the given element file into the paste buffer. Element files
5429 contain only a single @code{Element} definition, such as the
5430 ``newlib'' library uses.
5432 @item Netlist
5433 Loads a new netlist, replacing any current netlist.
5435 @item Revert
5436 Re-loads the current layout from its disk file, reverting any changes
5437 you may have made.
5439 @end table
5441 %end-doc */
5443 static int
5444 ActionLoadFrom (int argc, char **argv, int x, int y)
5446 char *function;
5447 char *name;
5448 char fname[256];
5450 if (argc < 2)
5451 AFAIL (loadfrom);
5453 function = argv[0];
5454 name = argv[1];
5456 HideCrosshair (True);
5458 if (strcasecmp (function, "ElementToBuffer") == 0)
5460 if (LoadElementToBuffer (PASTEBUFFER, name, True))
5461 SetMode (PASTEBUFFER_MODE);
5464 else if (strcasecmp (function, "LayoutToBuffer") == 0)
5466 if (LoadLayoutToBuffer (PASTEBUFFER, name))
5467 SetMode (PASTEBUFFER_MODE);
5470 else if (strcasecmp (function, "Layout") == 0)
5472 if (!PCB->Changed ||
5473 gui->confirm_dialog (_("OK to override layout data?"), 0))
5474 LoadPCB (name);
5477 else if (strcasecmp (function, "Netlist") == 0)
5479 if (PCB->Netlistname)
5480 SaveFree (PCB->Netlistname);
5481 PCB->Netlistname = StripWhiteSpaceAndDup (name);
5482 FreeLibraryMemory (&PCB->NetlistLib);
5483 if (!ReadNetlist (PCB->Netlistname))
5484 hid_action ("NetlistChanged");
5486 else if (strcasecmp (function, "Revert") == 0 && PCB->Filename
5487 && (!PCB->Changed
5488 || gui->confirm_dialog (_("OK to override changes?"), 0)))
5490 strcpy (fname, PCB->Filename); /*Calling LoadPCB(PCB->Filename) changes the content of PCB->Filename. */
5491 LoadPCB (fname);
5494 RestoreCrosshair (True);
5495 return 0;
5498 /* --------------------------------------------------------------------------- */
5500 static const char new_syntax[] = "New([name])";
5502 static const char new_help[] = "Starts a new layout.";
5504 /* %start-doc actions New
5506 If a name is not given, one is prompted for.
5508 %end-doc */
5510 static int
5511 ActionNew (int argc, char **argv, int x, int y)
5513 char *name = ARG (0);
5515 HideCrosshair (True);
5516 if (!PCB->Changed || gui->confirm_dialog (_("OK to clear layout data?"), 0))
5518 if (name)
5519 name = MyStrdup (name, "ActionNew");
5520 else
5521 name = gui->prompt_for (_("Enter the layout name:"), "");
5522 if (!name)
5523 return 1;
5525 /* do emergency saving
5526 * clear the old struct and allocate memory for the new one
5528 if (PCB->Changed && Settings.SaveInTMP)
5529 SaveInTMP ();
5530 RemovePCB (PCB);
5531 PCB = CreateNewPCB (True);
5532 PCB->Data->LayerN = DEF_LAYER;
5533 CreateNewPCBPost (PCB, 1);
5535 /* setup the new name and reset some values to default */
5536 PCB->Name = name; /* XXX memory leak */
5538 ResetStackAndVisibility ();
5539 CreateDefaultFont ();
5540 SetCrosshairRange (0, 0, PCB->MaxWidth, PCB->MaxHeight);
5541 CenterDisplay (PCB->MaxWidth / 2, PCB->MaxHeight / 2, False);
5542 ClearAndRedrawOutput ();
5544 hid_action ("PCBChanged");
5545 return 0;
5547 RestoreCrosshair (True);
5548 return 1;
5551 /* ---------------------------------------------------------------------------
5552 * no operation, just for testing purposes
5553 * syntax: Bell(volume)
5555 void
5556 ActionBell (char *volume)
5558 gui->beep ();
5561 /* --------------------------------------------------------------------------- */
5563 static const char pastebuffer_syntax[] =
5564 "PasteBuffer(AddSelected|Clear|1..MAX_BUFFER)\n"
5565 "PasteBuffer(Rotate, 1..3)\n"
5566 "PasteBuffer(Convert|Save|Restore|Mirror)\n"
5567 "PasteBuffer(ToLayout, X, Y, units)";
5569 static const char pastebuffer_help[] =
5570 "Various operations on the paste buffer.";
5572 /* %start-doc actions PasteBuffer
5574 There are a number of paste buffers; the actual limit is a
5575 compile-time constant @code{MAX_BUFFER} in @file{globalconst.h}. It
5576 is currently @code{5}. One of these is the ``current'' paste buffer,
5577 often referred to as ``the'' paste buffer.
5579 @table @code
5581 @item AddSelected
5582 Copies the selected objects to the current paste buffer.
5584 @item Clear
5585 Remove all objects from the current paste buffer.
5587 @item Convert
5588 Convert the current paste buffer to an element. Vias are converted to
5589 pins, lines are converted to pads.
5591 @item Restore
5592 Convert any elements in the paste buffer back to vias and lines.
5594 @item Mirror
5595 Flip all objects in the paste buffer vertically (up/down flip). To mirror
5596 horizontally, combine this with rotations.
5598 @item Rotate
5599 Rotates the current buffer. The number to pass is 1..3, where 1 means
5600 90 degrees counter clockwise, 2 means 180 degrees, and 3 means 90
5601 degrees clockwise (270 CCW).
5603 @item Save
5604 Saves any elements in the current buffer to the indicated file.
5606 @item ToLayout
5607 Pastes any elements in the current buffer to the indicated X, Y
5608 coordinates in the layout. The @code{X} and @code{Y} are treated like
5609 @code{delta} is for many other objects. For each, if it's prefixed by
5610 @code{+} or @code{-}, then that amount is relative to the last
5611 location. Otherwise, it's absolute. Units can be
5612 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
5613 units, currently 1/100 mil.
5616 @item 1..MAX_BUFFER
5617 Selects the given buffer to be the current paste buffer.
5619 @end table
5621 %end-doc */
5623 static int
5624 ActionPasteBuffer (int argc, char **argv, int x, int y)
5626 char *function = argc ? argv[0] : "";
5627 char *sbufnum = argc > 1 ? argv[1] : "";
5628 char *name;
5630 HideCrosshair (True);
5631 if (function)
5633 switch (GetFunctionID (function))
5635 /* clear contents of paste buffer */
5636 case F_Clear:
5637 ClearBuffer (PASTEBUFFER);
5638 break;
5640 /* copies objects to paste buffer */
5641 case F_AddSelected:
5642 AddSelectedToBuffer (PASTEBUFFER, 0, 0, False);
5643 break;
5645 /* converts buffer contents into an element */
5646 case F_Convert:
5647 ConvertBufferToElement (PASTEBUFFER);
5648 break;
5650 /* break up element for editing */
5651 case F_Restore:
5652 SmashBufferElement (PASTEBUFFER);
5653 break;
5655 /* Mirror buffer */
5656 case F_Mirror:
5657 MirrorBuffer (PASTEBUFFER);
5658 break;
5660 case F_Rotate:
5661 if (sbufnum)
5663 RotateBuffer (PASTEBUFFER, (BYTE) atoi (sbufnum));
5664 SetCrosshairRangeToBuffer ();
5666 break;
5668 case F_Save:
5669 if (PASTEBUFFER->Data->ElementN == 0)
5671 Message (_("Buffer has no elements!\n"));
5672 break;
5674 if (argc <= 1)
5675 name = gui->prompt_for ("Save as:", 0);
5676 else
5677 name = argv[1];
5680 FILE *exist;
5682 if ((exist = fopen (name, "r")))
5684 fclose (exist);
5685 if (gui->
5686 confirm_dialog (_("File exists! Ok to overwrite?"), 0))
5687 SaveBufferElements (name);
5689 else
5690 SaveBufferElements (name);
5692 break;
5694 case F_ToLayout:
5696 static int oldx = 0, oldy = 0;
5697 int x, y;
5698 Boolean r;
5700 if (argc == 1)
5702 x = y = 0;
5704 else if (argc == 3 || argc == 4)
5706 x = GetValue (ARG (1), ARG (3), &r);
5707 if (!r)
5708 x += oldx;
5709 y = GetValue (ARG (2), ARG (3), &r);
5710 if (!r)
5711 y += oldy;
5713 else
5715 RestoreCrosshair (True);
5716 AFAIL (pastebuffer);
5719 oldx = x;
5720 oldy = y;
5721 if (CopyPastebufferToLayout (x, y))
5722 SetChangedFlag (True);
5724 break;
5726 /* set number */
5727 default:
5729 int number = atoi (function);
5731 /* correct number */
5732 if (number)
5733 SetBufferNumber (number - 1);
5738 RestoreCrosshair (True);
5739 return 0;
5742 /* --------------------------------------------------------------------------- */
5744 static const char undo_syntax[] = "Undo()\n" "Undo(ClearList)";
5746 static const char undo_help[] = "Undo recent changes.";
5748 /* %start-doc actions Undo
5750 The unlimited undo feature of @code{Pcb} allows you to recover from
5751 most operations that materially affect you work. Calling
5752 @code{Undo()} without any parameter recovers from the last (non-undo)
5753 operation. @code{ClearList} is used to release the allocated
5754 memory. @code{ClearList} is called whenever a new layout is started or
5755 loaded. See also @code{Redo} and @code{Atomic}.
5757 Note that undo groups operations by serial number; changes with the
5758 same serial number will be undone (or redone) as a group. See
5759 @code{Atomic}.
5761 %end-doc */
5763 static int
5764 ActionUndo (int argc, char **argv, int x, int y)
5766 char *function = ARG (0);
5767 if (!function || !*function)
5769 /* don't allow undo in the middle of an operation */
5770 if (Crosshair.AttachedObject.State != STATE_FIRST)
5771 return 1;
5772 if (Crosshair.AttachedBox.State != STATE_FIRST
5773 && Settings.Mode != ARC_MODE)
5774 return 1;
5775 /* undo the last operation */
5777 HideCrosshair (True);
5778 if (Settings.Mode == POLYGON_MODE && Crosshair.AttachedPolygon.PointN)
5780 GoToPreviousPoint ();
5781 RestoreCrosshair (True);
5782 return 0;
5784 /* move anchor point if undoing during line creation */
5785 if (Settings.Mode == LINE_MODE)
5787 if (Crosshair.AttachedLine.State == STATE_SECOND)
5789 if (TEST_FLAG (AUTODRCFLAG, PCB))
5790 Undo (True); /* undo the connection find */
5791 Crosshair.AttachedLine.State = STATE_FIRST;
5792 SetLocalRef (0, 0, False);
5793 RestoreCrosshair (True);
5794 return 0;
5796 if (Crosshair.AttachedLine.State == STATE_THIRD)
5798 int type;
5799 void *ptr1, *ptr3, *ptrtmp;
5800 LineTypePtr ptr2;
5801 /* this search is guaranteed to succeed */
5802 SearchObjectByLocation (LINE_TYPE | RATLINE_TYPE, &ptr1,
5803 &ptrtmp, &ptr3,
5804 Crosshair.AttachedLine.Point1.X,
5805 Crosshair.AttachedLine.Point1.Y, 0);
5806 ptr2 = (LineTypePtr) ptrtmp;
5808 /* save both ends of line */
5809 Crosshair.AttachedLine.Point2.X = ptr2->Point1.X;
5810 Crosshair.AttachedLine.Point2.Y = ptr2->Point1.Y;
5811 if ((type = Undo (True)))
5812 SetChangedFlag (True);
5813 /* check that the undo was of the right type */
5814 if ((type & UNDO_CREATE) == 0)
5816 /* wrong undo type, restore anchor points */
5817 Crosshair.AttachedLine.Point2.X =
5818 Crosshair.AttachedLine.Point1.X;
5819 Crosshair.AttachedLine.Point2.Y =
5820 Crosshair.AttachedLine.Point1.Y;
5821 RestoreCrosshair (True);
5822 return 0;
5824 /* move to new anchor */
5825 Crosshair.AttachedLine.Point1.X =
5826 Crosshair.AttachedLine.Point2.X;
5827 Crosshair.AttachedLine.Point1.Y =
5828 Crosshair.AttachedLine.Point2.Y;
5829 /* check if an intermediate point was removed */
5830 if (type & UNDO_REMOVE)
5832 /* this search should find the restored line */
5833 SearchObjectByLocation (LINE_TYPE | RATLINE_TYPE, &ptr1,
5834 &ptrtmp,
5835 &ptr3,
5836 Crosshair.AttachedLine.Point2.X,
5837 Crosshair.AttachedLine.Point2.Y, 0);
5838 ptr2 = (LineTypePtr) ptrtmp;
5839 Crosshair.AttachedLine.Point1.X =
5840 Crosshair.AttachedLine.Point2.X = ptr2->Point2.X;
5841 Crosshair.AttachedLine.Point1.Y =
5842 Crosshair.AttachedLine.Point2.Y = ptr2->Point2.Y;
5844 FitCrosshairIntoGrid (Crosshair.X, Crosshair.Y);
5845 AdjustAttachedObjects ();
5846 if (--addedLines == 0)
5848 Crosshair.AttachedLine.State = STATE_SECOND;
5849 lastLayer = CURRENT;
5851 else
5853 /* this search is guaranteed to succeed too */
5854 SearchObjectByLocation (LINE_TYPE | RATLINE_TYPE, &ptr1,
5855 &ptrtmp,
5856 &ptr3,
5857 Crosshair.AttachedLine.Point1.X,
5858 Crosshair.AttachedLine.Point1.Y, 0);
5859 ptr2 = (LineTypePtr) ptrtmp;
5860 lastLayer = (LayerTypePtr) ptr1;
5862 RestoreCrosshair (True);
5863 return 0;
5866 if (Settings.Mode == ARC_MODE)
5868 if (Crosshair.AttachedBox.State == STATE_SECOND)
5870 Crosshair.AttachedBox.State = STATE_FIRST;
5871 RestoreCrosshair (True);
5872 return 0;
5874 if (Crosshair.AttachedBox.State == STATE_THIRD)
5876 void *ptr1, *ptr2, *ptr3;
5877 BoxTypePtr bx;
5878 /* guaranteed to succeed */
5879 SearchObjectByLocation (ARC_TYPE, &ptr1, &ptr2, &ptr3,
5880 Crosshair.AttachedBox.Point1.X,
5881 Crosshair.AttachedBox.Point1.Y, 0);
5882 bx = GetArcEnds ((ArcTypePtr) ptr2);
5883 Crosshair.AttachedBox.Point1.X =
5884 Crosshair.AttachedBox.Point2.X = bx->X1;
5885 Crosshair.AttachedBox.Point1.Y =
5886 Crosshair.AttachedBox.Point2.Y = bx->Y1;
5887 AdjustAttachedObjects ();
5888 if (--addedLines == 0)
5889 Crosshair.AttachedBox.State = STATE_SECOND;
5892 /* undo the last destructive operation */
5893 if (Undo (True))
5894 SetChangedFlag (True);
5896 else if (function)
5898 switch (GetFunctionID (function))
5900 /* clear 'undo objects' list */
5901 case F_ClearList:
5902 ClearUndoList (False);
5903 break;
5906 RestoreCrosshair (True);
5907 return 0;
5910 /* --------------------------------------------------------------------------- */
5912 static const char redo_syntax[] = "Redo()";
5914 static const char redo_help[] = "Redo recent \"undo\" operations.";
5916 /* %start-doc actions Redo
5918 This routine allows you to recover from the last undo command. You
5919 might want to do this if you thought that undo was going to revert
5920 something other than what it actually did (in case you are confused
5921 about which operations are un-doable), or if you have been backing up
5922 through a long undo list and over-shoot your stopping point. Any
5923 change that is made since the undo in question will trim the redo
5924 list. For example if you add ten lines, then undo three of them you
5925 could use redo to put them back, but if you move a line on the board
5926 before performing the redo, you will lose the ability to "redo" the
5927 three "undone" lines.
5929 %end-doc */
5931 static int
5932 ActionRedo (int argc, char **argv, int x, int y)
5934 if ((Settings.Mode == POLYGON_MODE &&
5935 Crosshair.AttachedPolygon.PointN) ||
5936 Crosshair.AttachedLine.State == STATE_SECOND)
5937 return 1;
5938 HideCrosshair (True);
5939 if (Redo (True))
5941 SetChangedFlag (True);
5942 if (Settings.Mode == LINE_MODE &&
5943 Crosshair.AttachedLine.State != STATE_FIRST)
5945 LineTypePtr line = &CURRENT->Line[CURRENT->LineN - 1];
5946 Crosshair.AttachedLine.Point1.X =
5947 Crosshair.AttachedLine.Point2.X = line->Point2.X;
5948 Crosshair.AttachedLine.Point1.Y =
5949 Crosshair.AttachedLine.Point2.Y = line->Point2.Y;
5950 addedLines++;
5953 RestoreCrosshair (True);
5954 return 0;
5957 /* --------------------------------------------------------------------------- */
5959 static const char polygon_syntax[] = "Polygon(Close|PreviousPoint)";
5961 static const char polygon_help[] = "Some polygon related stuff.";
5963 /* %start-doc actions Polygon
5965 Polygons need a special action routine to make life easier.
5967 @table @code
5969 @item Close
5970 Creates the final segment of the polygon. This may fail if clipping
5971 to 45 degree lines is switched on, in which case a warning is issued.
5973 @item PreviousPoint
5974 Resets the newly entered corner to the previous one. The Undo action
5975 will call Polygon(PreviousPoint) when appropriate to do so.
5977 @end table
5979 %end-doc */
5981 static int
5982 ActionPolygon (int argc, char **argv, int x, int y)
5984 char *function = ARG (0);
5985 if (function && Settings.Mode == POLYGON_MODE)
5987 HideCrosshair (True);
5988 switch (GetFunctionID (function))
5990 /* close open polygon if possible */
5991 case F_Close:
5992 ClosePolygon ();
5993 break;
5995 /* go back to the previous point */
5996 case F_PreviousPoint:
5997 GoToPreviousPoint ();
5998 break;
6000 RestoreCrosshair (True);
6002 return 0;
6005 /* --------------------------------------------------------------------------- */
6007 static const char routestyle_syntax[] = "RouteStyle(1|2|3|4)";
6009 static const char routestyle_help[] =
6010 "Copies the indicated routing style into the current sizes.";
6012 /* %start-doc actions RouteStyle
6014 %end-doc */
6016 static int
6017 ActionRouteStyle (int argc, char **argv, int x, int y)
6019 char *str = ARG (0);
6020 RouteStyleType *rts;
6021 int number;
6023 if (str)
6025 number = atoi (str);
6026 if (number > 0 && number <= NUM_STYLES)
6028 rts = &PCB->RouteStyle[number - 1];
6029 SetLineSize (rts->Thick);
6030 SetViaSize (rts->Diameter, True);
6031 SetViaDrillingHole (rts->Hole, True);
6032 SetKeepawayWidth (rts->Keepaway);
6035 return 0;
6039 /* --------------------------------------------------------------------------- */
6041 static const char moveobject_syntax[] = "MoveObject(X,Y,dim)";
6043 static const char moveobject_help[] = "Moves the object under the crosshair.";
6045 /* %start-doc actions MoveObject
6047 The @code{X} and @code{Y} are treated like @code{delta} is for many
6048 other objects. For each, if it's prefixed by @code{+} or @code{-},
6049 then that amount is relative. Otherwise, it's absolute. Units can be
6050 @code{mil} or @code{mm}; if unspecified, units are PCB's internal
6051 units, currently 1/100 mil.
6053 %end-doc */
6055 static int
6056 ActionMoveObject (int argc, char **argv, int x, int y)
6058 char *x_str = ARG (0);
6059 char *y_str = ARG (1);
6060 char *units = ARG (2);
6061 LocationType nx, ny;
6062 Boolean r1, r2;
6063 void *ptr1, *ptr2, *ptr3;
6064 int type;
6066 ny = GetValue (y_str, units, &r1);
6067 nx = GetValue (x_str, units, &r2);
6069 type = SearchScreen (x, y, MOVE_TYPES, &ptr1, &ptr2, &ptr3);
6070 if (type == NO_TYPE)
6072 Message (_("Nothing found under crosshair\n"));
6073 return 1;
6075 if (r1)
6076 nx -= x;
6077 if (r2)
6078 ny -= y;
6079 Crosshair.AttachedObject.RubberbandN = 0;
6080 if (TEST_FLAG (RUBBERBANDFLAG, PCB))
6081 LookupRubberbandLines (type, ptr1, ptr2, ptr3);
6082 if (type == ELEMENT_TYPE)
6083 LookupRatLines (type, ptr1, ptr2, ptr3);
6084 MoveObjectAndRubberband (type, ptr1, ptr2, ptr3, nx, ny);
6085 SetChangedFlag (True);
6086 return 0;
6089 /* --------------------------------------------------------------------------- */
6091 static const char movetocurrentlayer_syntax[] =
6092 "MoveToCurrentLayer(Object|SelectedObjects)";
6094 static const char movetocurrentlayer_help[] =
6095 "Moves objects to the current layer.";
6097 /* %start-doc actions MoveToCurrentLayer
6099 Note that moving an element from a component layer to a solder layer,
6100 or from solder to component, won't automatically flip it. Use the
6101 @code{Flip()} action to do that.
6103 %end-doc */
6105 static int
6106 ActionMoveToCurrentLayer (int argc, char **argv, int x, int y)
6108 char *function = ARG (0);
6109 if (function)
6111 HideCrosshair (True);
6112 switch (GetFunctionID (function))
6114 case F_Object:
6116 int type;
6117 void *ptr1, *ptr2, *ptr3;
6119 gui->get_coords ("Select an Object", &x, &y);
6120 if ((type =
6121 SearchScreen (x, y, MOVETOLAYER_TYPES,
6122 &ptr1, &ptr2, &ptr3)) != NO_TYPE)
6123 if (MoveObjectToLayer (type, ptr1, ptr2, ptr3, CURRENT, False))
6124 SetChangedFlag (True);
6125 break;
6128 case F_SelectedObjects:
6129 case F_Selected:
6130 if (MoveSelectedObjectsToLayer (CURRENT))
6131 SetChangedFlag (True);
6132 break;
6134 RestoreCrosshair (True);
6136 return 0;
6140 static const char setsame_syntax[] = "SetSame()";
6142 static const char setsame_help[] =
6143 "Sets current layer and sizes to match indicated item.";
6145 /* %start-doc actions SetSame
6147 When invoked over any line, arc, polygon, or via, this changes the
6148 current layer to be the layer that item is on, and changes the current
6149 sizes (thickness, keepaway, drill, etc) according to that item.
6151 %end-doc */
6153 static int
6154 ActionSetSame (int argc, char **argv, int x, int y)
6156 void *ptr1, *ptr2, *ptr3;
6157 int type;
6158 LayerTypePtr layer = CURRENT;
6160 type = SearchScreen (x, y, CLONE_TYPES, &ptr1, &ptr2, &ptr3);
6161 /* set layer current and size from line or arc */
6162 switch (type)
6164 case LINE_TYPE:
6165 HideCrosshair (True);
6166 Settings.LineThickness = ((LineTypePtr) ptr2)->Thickness;
6167 Settings.Keepaway = ((LineTypePtr) ptr2)->Clearance / 2;
6168 layer = (LayerTypePtr) ptr1;
6169 if (Settings.Mode != LINE_MODE)
6170 SetMode (LINE_MODE);
6171 RestoreCrosshair (True);
6172 hid_action ("RouteStyleChanged");
6173 break;
6175 case ARC_TYPE:
6176 HideCrosshair (True);
6177 Settings.LineThickness = ((ArcTypePtr) ptr2)->Thickness;
6178 Settings.Keepaway = ((ArcTypePtr) ptr2)->Clearance / 2;
6179 layer = (LayerTypePtr) ptr1;
6180 if (Settings.Mode != ARC_MODE)
6181 SetMode (ARC_MODE);
6182 RestoreCrosshair (True);
6183 hid_action ("RouteStyleChanged");
6184 break;
6186 case POLYGON_TYPE:
6187 layer = (LayerTypePtr) ptr1;
6188 break;
6190 case VIA_TYPE:
6191 HideCrosshair (True);
6192 Settings.ViaThickness = ((PinTypePtr) ptr2)->Thickness;
6193 Settings.ViaDrillingHole = ((PinTypePtr) ptr2)->DrillingHole;
6194 Settings.Keepaway = ((PinTypePtr) ptr2)->Clearance / 2;
6195 if (Settings.Mode != VIA_MODE)
6196 SetMode (VIA_MODE);
6197 RestoreCrosshair (True);
6198 hid_action ("RouteStyleChanged");
6199 break;
6201 default:
6202 return 1;
6204 if (layer != CURRENT)
6206 ChangeGroupVisibility (GetLayerNumber (PCB->Data, layer), True, True);
6207 ClearAndRedrawOutput ();
6209 return 0;
6213 /* --------------------------------------------------------------------------- */
6215 static const char setflag_syntax[] =
6216 "SetFlag(Object|Selected|SelectedObjects, flag)\n"
6217 "SetFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6218 "SetFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6219 "SetFlag(SelectedElements, flag)\n"
6220 "flag = square | octagon | thermal | join";
6222 static const char setflag_help[] = "Sets flags on objects.";
6224 /* %start-doc actions SetFlag
6226 Turns the given flag on, regardless of its previous setting. See
6227 @code{ChangeFlag}.
6229 @example
6230 SetFlag(SelectedPins,thermal)
6231 @end example
6233 %end-doc */
6235 static int
6236 ActionSetFlag (int argc, char **argv, int x, int y)
6238 char *function = ARG (0);
6239 char *flag = ARG (1);
6240 ChangeFlag (function, flag, 1, "SetFlag");
6241 return 0;
6244 /* --------------------------------------------------------------------------- */
6246 static const char clrflag_syntax[] =
6247 "ClrFlag(Object|Selected|SelectedObjects, flag)\n"
6248 "ClrFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n"
6249 "ClrFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n"
6250 "ClrFlag(SelectedElements, flag)\n"
6251 "flag = square | octagon | thermal | join";
6253 static const char clrflag_help[] = "Clears flags on objects.";
6255 /* %start-doc actions ClrFlag
6257 Turns the given flag off, regardless of its previous setting. See
6258 @code{ChangeFlag}.
6260 @example
6261 ClrFlag(SelectedLines,join)
6262 @end example
6264 %end-doc */
6266 static int
6267 ActionClrFlag (int argc, char **argv, int x, int y)
6269 char *function = ARG (0);
6270 char *flag = ARG (1);
6271 ChangeFlag (function, flag, 0, "ClrFlag");
6272 return 0;
6275 /* --------------------------------------------------------------------------- */
6277 static const char changeflag_syntax[] =
6278 "ChangeFlag(Object|Selected|SelectedObjects, flag, value)\n"
6279 "ChangeFlag(SelectedLines|SelectedPins|SelectedVias, flag, value)\n"
6280 "ChangeFlag(SelectedPads|SelectedTexts|SelectedNames, flag, value)\n"
6281 "ChangeFlag(SelectedElements, flag, value)\n"
6282 "flag = square | octagon | thermal | join\n" "value = 0 | 1";
6284 static const char changeflag_help[] = "Sets or clears flags on objects.";
6286 /* %start-doc actions ChangeFlag
6288 Toggles the given flag on the indicated object(s). The flag may be
6289 one of the flags listed above (square, octagon, thermal, join). The
6290 value may be the number 0 or 1. If the value is 0, the flag is
6291 cleared. If the value is 1, the flag is set.
6293 %end-doc */
6295 static int
6296 ActionChangeFlag (int argc, char **argv, int x, int y)
6298 char *function = ARG (0);
6299 char *flag = ARG (1);
6300 int value = argc > 2 ? atoi (argv[2]) : -1;
6301 if (value != 0 && value != 1)
6302 AFAIL (changeflag);
6304 ChangeFlag (function, flag, value, "ChangeFlag");
6305 return 0;
6309 static void
6310 ChangeFlag (char *what, char *flag_name, int value, char *cmd_name)
6312 Boolean (*set_object) (int, void *, void *, void *);
6313 Boolean (*set_selected) (int);
6315 if (NSTRCMP (flag_name, "square") == 0)
6317 set_object = value ? SetObjectSquare : ClrObjectSquare;
6318 set_selected = value ? SetSelectedSquare : ClrSelectedSquare;
6320 else if (NSTRCMP (flag_name, "octagon") == 0)
6322 set_object = value ? SetObjectOctagon : ClrObjectOctagon;
6323 set_selected = value ? SetSelectedOctagon : ClrSelectedOctagon;
6325 else if (NSTRCMP (flag_name, "join") == 0)
6327 /* Note: these are backwards, because the flag is "clear" but
6328 the command is "join". */
6329 set_object = value ? ClrObjectJoin : SetObjectJoin;
6330 set_selected = value ? ClrSelectedJoin : SetSelectedJoin;
6332 else
6334 Message (_("%s(): Flag \"%s\" is not valid\n"), cmd_name, flag_name);
6335 return;
6338 HideCrosshair (True);
6339 switch (GetFunctionID (what))
6341 case F_Object:
6343 int type;
6344 void *ptr1, *ptr2, *ptr3;
6346 if ((type =
6347 SearchScreen (Crosshair.X, Crosshair.Y, CHANGESIZE_TYPES,
6348 &ptr1, &ptr2, &ptr3)) != NO_TYPE)
6349 if (TEST_FLAG (LOCKFLAG, (PinTypePtr) ptr2))
6350 Message (_("Sorry, the object is locked\n"));
6351 if (set_object (type, ptr1, ptr2, ptr3))
6352 SetChangedFlag (True);
6353 break;
6356 case F_SelectedVias:
6357 if (set_selected (VIA_TYPE))
6358 SetChangedFlag (True);
6359 break;
6361 case F_SelectedPins:
6362 if (set_selected (PIN_TYPE))
6363 SetChangedFlag (True);
6364 break;
6366 case F_SelectedPads:
6367 if (set_selected (PAD_TYPE))
6368 SetChangedFlag (True);
6369 break;
6371 case F_SelectedLines:
6372 if (set_selected (LINE_TYPE))
6373 SetChangedFlag (True);
6374 break;
6376 case F_SelectedTexts:
6377 if (set_selected (TEXT_TYPE))
6378 SetChangedFlag (True);
6379 break;
6381 case F_SelectedNames:
6382 if (set_selected (ELEMENTNAME_TYPE))
6383 SetChangedFlag (True);
6384 break;
6386 case F_SelectedElements:
6387 if (set_selected (ELEMENT_TYPE))
6388 SetChangedFlag (True);
6389 break;
6391 case F_Selected:
6392 case F_SelectedObjects:
6393 if (set_selected (CHANGESIZE_TYPES))
6394 SetChangedFlag (True);
6395 break;
6397 RestoreCrosshair (True);
6401 /* --------------------------------------------------------------------------- */
6403 static const char executefile_syntax[] = "ExecuteFile(filename)";
6405 static const char executefile_help[] = "Run actions from the given file.";
6407 /* %start-doc actions ExecuteFile
6409 Lines starting with @code{#} are ignored.
6411 %end-doc */
6413 static int
6414 ActionExecuteFile (int argc, char **argv, int x, int y)
6416 FILE *fp;
6417 char *fname;
6418 char line[256];
6419 int n = 0;
6420 char *sp;
6422 if (argc != 1)
6423 AFAIL (executefile);
6425 fname = argv[0];
6427 if ((fp = fopen (fname, "r")) == NULL)
6429 fprintf (stderr, "Could not open actions file \"%s\".\n", fname);
6430 return 1;
6433 while (fgets (line, sizeof (line), fp) != NULL)
6435 n++;
6436 sp = line;
6438 /* eat the trailing newline */
6439 while (*sp && *sp != '\r' && *sp != '\n')
6440 sp++;
6441 *sp = '\0';
6443 /* eat leading spaces and tabs */
6444 sp = line;
6445 while (*sp && (*sp == ' ' || *sp == '\t'))
6446 sp++;
6449 * if we have anything left and its not a comment line
6450 * then execute it
6453 if (*sp && *sp != '#')
6455 Message ("%s : line %-3d : \"%s\"\n", fname, n, sp);
6456 hid_parse_actions (sp, 0);
6460 fclose (fp);
6461 return 0;
6464 /* --------------------------------------------------------------------------- */
6466 static int
6467 ActionPSCalib (int argc, char **argv, int x, int y)
6469 HID *ps = hid_find_exporter ("ps");
6470 ps->calibrate (0.0,0.0);
6471 return 0;
6474 /* --------------------------------------------------------------------------- */
6476 HID_Action action_action_list[] = {
6477 {"AddRats", 0, ActionAddRats,
6478 addrats_help, addrats_syntax}
6480 {"Atomic", 0, ActionAtomic,
6481 atomic_help, atomic_syntax}
6483 {"AutoPlaceSelected", 0, ActionAutoPlaceSelected,
6484 autoplace_help, autoplace_syntax}
6486 {"AutoRoute", 0, ActionAutoRoute,
6487 autoroute_help, autoroute_syntax}
6489 {"ChangeClearSize", 0, ActionChangeClearSize,
6490 changeclearsize_help, changeclearsize_syntax}
6492 {"ChangeDrillSize", 0, ActionChange2ndSize,
6493 changedrillsize_help, changedrillsize_syntax}
6495 {"ChangeHole", 0, ActionChangeHole,
6496 changehold_help, changehold_syntax}
6498 {"ChangeJoin", 0, ActionChangeJoin,
6499 changejoin_help, changejoin_syntax}
6501 {"ChangeName", 0, ActionChangeName,
6502 changename_help, changename_syntax}
6504 {"ChangePaste", 0, ActionChangePaste,
6505 changepaste_help, changepaste_syntax}
6507 {"ChangePinName", 0, ActionChangePinName,
6508 changepinname_help, changepinname_syntax}
6510 {"ChangeSize", 0, ActionChangeSize,
6511 changesize_help, changesize_syntax}
6513 {"ChangeSquare", 0, ActionChangeSquare,
6514 changesquare_help, changesquare_syntax}
6516 {"ChangeOctagon", 0, ActionChangeOctagon,
6517 changeoctagon_help, changeoctagon_syntax}
6519 {"ClearSquare", 0, ActionClearSquare,
6520 clearsquare_help, clearsquare_syntax}
6522 {"ClearOctagon", 0, ActionClearOctagon,
6523 clearoctagon_help, clearoctagon_syntax}
6525 {"Connection", 0, ActionConnection,
6526 connection_help, connection_syntax}
6528 {"DeleteRats", 0, ActionDeleteRats,
6529 deleterats_help, deleterats_syntax}
6531 {"DisperseElements", 0, ActionDisperseElements,
6532 disperseelements_help, disperseelements_syntax}
6534 {"Display", 0, ActionDisplay,
6535 display_help, display_syntax}
6537 {"DRC", 0, ActionDRCheck,
6538 drc_help, drc_syntax}
6540 {"DumpLibrary", 0, ActionDumpLibrary,
6541 dumplibrary_help, dumplibrary_syntax}
6543 {"ExecuteFile", 0, ActionExecuteFile,
6544 executefile_help, executefile_syntax}
6546 {"Flip", "Click on Object or Flip Point", ActionFlip,
6547 flip_help, flip_syntax}
6549 {"LoadFrom", 0, ActionLoadFrom,
6550 loadfrom_help, loadfrom_syntax}
6552 {"MarkCrosshair", 0, ActionMarkCrosshair,
6553 markcrosshair_help, markcrosshair_syntax}
6555 {"Message", 0, ActionMessage,
6556 message_help, message_syntax}
6558 {"MinMaskGap", 0, ActionMinMaskGap,
6559 minmaskgap_help, minmaskgap_syntax}
6561 {"Mode", 0, ActionMode,
6562 mode_help, mode_syntax}
6564 {"MorphPolygon", 0, ActionMorphPolygon,
6565 morphpolygon_help, morphpolygon_syntax}
6567 {"PasteBuffer", 0, ActionPasteBuffer,
6568 pastebuffer_help, pastebuffer_syntax}
6570 {"Quit", 0, ActionQuit,
6571 quit_help, quit_syntax}
6573 {"RemoveSelected", 0, ActionRemoveSelected,
6574 removeselected_help, removeselected_syntax}
6576 {"Renumber", 0, ActionRenumber,
6577 renumber_help, renumber_syntax}
6579 {"RipUp", 0, ActionRipUp,
6580 ripup_help, ripup_syntax}
6582 {"Select", 0, ActionSelect,
6583 select_help, select_syntax}
6585 {"Unselect", 0, ActionUnselect,
6586 unselect_help, unselect_syntax}
6588 {"SaveSettings", 0, ActionSaveSettings,
6589 savesettings_help, savesettings_syntax}
6591 {"SaveTo", 0, ActionSaveTo,
6592 saveto_help, saveto_syntax}
6594 {"SetSquare", 0, ActionSetSquare,
6595 setsquare_help, setsquare_syntax}
6597 {"SetOctagon", 0, ActionSetOctagon,
6598 setoctagon_help, setoctagon_syntax}
6600 {"SetThermal", 0, ActionSetThermal,
6601 setthermal_help, setthermal_syntax}
6603 {"SetValue", 0, ActionSetValue,
6604 setvalue_help, setvalue_syntax}
6606 {"ToggleHideName", 0, ActionToggleHideName,
6607 togglehidename_help, togglehidename_syntax}
6609 {"Undo", 0, ActionUndo,
6610 undo_help, undo_syntax}
6612 {"Redo", 0, ActionRedo,
6613 redo_help, redo_syntax}
6615 {"SetSame", "Select item to use attributes from", ActionSetSame,
6616 setsame_help, setsame_syntax}
6618 {"SetFlag", 0, ActionSetFlag,
6619 setflag_help, setflag_syntax}
6621 {"ClrFlag", 0, ActionClrFlag,
6622 clrflag_help, clrflag_syntax}
6624 {"ChangeFlag", 0, ActionChangeFlag,
6625 changeflag_help, changeflag_syntax}
6627 {"Polygon", 0, ActionPolygon,
6628 polygon_help, polygon_syntax}
6630 {"RouteStyle", 0, ActionRouteStyle,
6631 routestyle_help, routestyle_syntax}
6633 {"MoveObject", "Select an Object", ActionMoveObject,
6634 moveobject_help, moveobject_syntax}
6636 {"MoveToCurrentLayer", 0, ActionMoveToCurrentLayer,
6637 movetocurrentlayer_help, movetocurrentlayer_syntax}
6639 {"New", 0, ActionNew,
6640 new_help, new_syntax}
6642 {"pscalib", 0, ActionPSCalib}
6646 REGISTER_ACTIONS (action_action_list)