pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00035 #ifdef HAVE_CONFIG_H 00036 #include "config.h" 00037 #endif 00038 00039 #include "global.h" 00040 00041 #include "action.h" 00042 #include "autoplace.h" 00043 #include "autoroute.h" 00044 #include "buffer.h" 00045 #include "change.h" 00046 #include "copy.h" 00047 #include "create.h" 00048 #include "crosshair.h" 00049 #include "data.h" 00050 #include "draw.h" 00051 #include "error.h" 00052 #include "file.h" 00053 #include "find.h" 00054 #include "hid.h" 00055 #include "insert.h" 00056 #include "line.h" 00057 #include "mymem.h" 00058 #include "misc.h" 00059 #include "mirror.h" 00060 #include "move.h" 00061 #include "polygon.h" 00062 /*#include "print.h"*/ 00063 #include "rats.h" 00064 #include "remove.h" 00065 #include "report.h" 00066 #include "rotate.h" 00067 #include "rubberband.h" 00068 #include "search.h" 00069 #include "select.h" 00070 #include "set.h" 00071 #include "thermal.h" 00072 #include "undo.h" 00073 #include "rtree.h" 00074 #include "macro.h" 00075 #include "pcb-printf.h" 00076 00077 #include <assert.h> 00078 #include <stdlib.h> /* rand() */ 00079 00080 #ifdef HAVE_LIBDMALLOC 00081 #include <dmalloc.h> 00082 #endif 00083 00084 /* for fork() and friends */ 00085 #ifdef HAVE_UNISTD_H 00086 #include <unistd.h> 00087 #endif 00088 00089 #ifdef HAVE_SYS_WAIT_H 00090 #include <sys/wait.h> 00091 #endif 00092 00093 /* --------------------------------------------------------------------------- 00094 * some local types 00095 */ 00096 typedef enum 00097 { 00098 F_AddSelected, 00099 F_All, 00100 F_AllConnections, 00101 F_AllRats, 00102 F_AllUnusedPins, 00103 F_Arc, 00104 F_Arrow, 00105 F_Block, 00106 F_Description, 00107 F_Cancel, 00108 F_Center, 00109 F_Clear, 00110 F_ClearAndRedraw, 00111 F_ClearList, 00112 F_Close, 00113 F_Found, 00114 F_Connection, 00115 F_Convert, 00116 F_Copy, 00117 F_CycleClip, 00118 F_CycleCrosshair, 00119 F_DeleteRats, 00120 F_Drag, 00121 F_DrillReport, 00122 F_Element, 00123 F_ElementByName, 00124 F_ElementConnections, 00125 F_ElementToBuffer, 00126 F_Escape, 00127 F_Find, 00128 F_FlipElement, 00129 F_FoundPins, 00130 F_Grid, 00131 F_InsertPoint, 00132 F_Layer, 00133 F_Layout, 00134 F_LayoutAs, 00135 F_LayoutToBuffer, 00136 F_Line, 00137 F_LineSize, 00138 F_Lock, 00139 F_Mirror, 00140 F_Move, 00141 F_NameOnPCB, 00142 F_Netlist, 00143 F_NetByName, 00144 F_None, 00145 F_Notify, 00146 F_Object, 00147 F_ObjectByName, 00148 F_PasteBuffer, 00149 F_PadByName, 00150 F_PinByName, 00151 F_PinOrPadName, 00152 F_Pinout, 00153 F_Polygon, 00154 F_PolygonHole, 00155 F_PreviousPoint, 00156 F_RatsNest, 00157 F_Rectangle, 00158 F_Redraw, 00159 F_Release, 00160 F_Revert, 00161 F_Remove, 00162 F_RemoveSelected, 00163 F_Report, 00164 F_Reset, 00165 F_ResetLinesAndPolygons, 00166 F_ResetPinsViasAndPads, 00167 F_Restore, 00168 F_Rotate, 00169 F_Save, 00170 F_Selected, 00171 F_SelectedArcs, 00172 F_SelectedElements, 00173 F_SelectedLines, 00174 F_SelectedNames, 00175 F_SelectedObjects, 00176 F_SelectedPads, 00177 F_SelectedPins, 00178 F_SelectedTexts, 00179 F_SelectedVias, 00180 F_SelectedRats, 00181 F_Stroke, 00182 F_Text, 00183 F_TextByName, 00184 F_TextScale, 00185 F_Thermal, 00186 F_ToLayout, 00187 F_ToggleAllDirections, 00188 F_ToggleAutoDRC, 00189 F_ToggleClearLine, 00190 F_ToggleFullPoly, 00191 F_ToggleGrid, 00192 F_ToggleHideNames, 00193 F_ToggleMask, 00194 F_ToggleName, 00195 F_ToggleObject, 00196 F_ToggleShowDRC, 00197 F_ToggleLiveRoute, 00198 F_ToggleRubberBandMode, 00199 F_ToggleStartDirection, 00200 F_ToggleSnapPin, 00201 F_ToggleThindraw, 00202 F_ToggleLockNames, 00203 F_ToggleOnlyNames, 00204 F_ToggleThindrawPoly, 00205 F_ToggleOrthoMove, 00206 F_ToggleLocalRef, 00207 F_ToggleCheckPlanes, 00208 F_ToggleUniqueNames, 00209 F_Via, 00210 F_ViaByName, 00211 F_Value, 00212 F_ViaDrillingHole, 00213 F_ViaSize, 00214 F_Zoom, 00215 F_ThroughHole, 00216 F_BuriedVias, 00217 F_ToggleAutoBuriedVias 00218 } 00219 FunctionID; 00220 00221 typedef struct /* used to identify subfunctions */ 00222 { 00223 char *Identifier; 00224 FunctionID ID; 00225 } 00226 FunctionType; 00227 00228 /* --------------------------------------------------------------------------- */ 00229 00230 /* %start-doc actions 00delta 00231 00232 Many actions take a @code{delta} parameter as the last parameter, 00233 which is an amount to change something. That @code{delta} may include 00234 units, as an additional parameter, such as @code{Action(Object,5,mm)}. 00235 If no units are specified, the default is PCB's native units 00236 (currently 1/100 mil). Also, if the delta is prefixed by @code{+} or 00237 @code{-}, the size is increased or decreased by that amount. 00238 Otherwise, the size size is set to the given amount. 00239 00240 @example 00241 Action(Object,5,mil) 00242 Action(Object,+0.5,mm) 00243 Action(Object,-1) 00244 @end example 00245 00246 Actions which take a @code{delta} parameter which do not accept all 00247 these options will specify what they do take. 00248 00249 %end-doc */ 00250 00251 /* %start-doc actions 00objects 00252 00253 Many actions act on indicated objects on the board. They will have 00254 parameters like @code{ToggleObject} or @code{SelectedVias} to indicate 00255 what group of objects they act on. Unless otherwise specified, these 00256 parameters are defined as follows: 00257 00258 @table @code 00259 00260 @item Object 00261 @itemx ToggleObject 00262 Affects the object under the mouse pointer. If this action is invoked 00263 from a menu or script, the user will be prompted to click on an 00264 object, which is then the object affected. 00265 00266 @item Selected 00267 @itemx SelectedObjects 00268 00269 Affects all objects which are currently selected. At least, all 00270 selected objects for which the given action makes sense. 00271 00272 @item SelectedPins 00273 @itemx SelectedVias 00274 @itemx Selected@var{Type} 00275 @itemx @i{etc} 00276 Affects all objects which are both selected and of the @var{Type} specified. 00277 00278 @end table 00279 00280 %end-doc */ 00281 00282 /* %start-doc actions 00macros 00283 00284 @macro pinshapes 00285 00286 Pins, pads, and vias can have various shapes. All may be round. Pins 00287 and pads may be square (obviously "square" pads are usually 00288 rectangular). Pins and vias may be octagonal. When you change a 00289 shape flag of an element, you actually change all of its pins and 00290 pads. 00291 00292 Note that the square flag takes precedence over the octagon flag, 00293 thus, if both the square and octagon flags are set, the object is 00294 square. When the square flag is cleared, the pins and pads will be 00295 either round or, if the octagon flag is set, octagonal. 00296 00297 @end macro 00298 00299 %end-doc */ 00300 00301 /* --------------------------------------------------------------------------- 00302 * some local identifiers 00303 */ 00304 static PointType InsertedPoint; 00305 static LayerType *lastLayer; 00306 static struct 00307 { 00308 PolygonType *poly; 00309 LineType line; 00310 } 00311 fake; 00312 00313 static struct 00314 { 00315 Coord X, Y; 00316 Cardinal Buffer; 00317 bool Click; 00318 bool Moving; /* selected type clicked on */ 00319 int Hit; /* move type clicked on */ 00320 void *ptr1; 00321 void *ptr2; 00322 void *ptr3; 00323 } 00324 Note; 00325 00326 static int defer_updates = 0; 00327 static int defer_needs_update = 0; 00328 00329 static Cardinal polyIndex = 0; 00330 static bool saved_mode = false; 00331 #ifdef HAVE_LIBSTROKE 00332 static bool mid_stroke = false; 00333 static BoxType StrokeBox; 00334 #endif 00335 static FunctionType Functions[] = { 00336 {"AddSelected", F_AddSelected}, 00337 {"All", F_All}, 00338 {"AllConnections", F_AllConnections}, 00339 {"AllRats", F_AllRats}, 00340 {"AllUnusedPins", F_AllUnusedPins}, 00341 {"Arc", F_Arc}, 00342 {"Arrow", F_Arrow}, 00343 {"Block", F_Block}, 00344 {"Description", F_Description}, 00345 {"Cancel", F_Cancel}, 00346 {"Center", F_Center}, 00347 {"Clear", F_Clear}, 00348 {"ClearAndRedraw", F_ClearAndRedraw}, 00349 {"ClearList", F_ClearList}, 00350 {"Close", F_Close}, 00351 {"Found", F_Found}, 00352 {"Connection", F_Connection}, 00353 {"Convert", F_Convert}, 00354 {"Copy", F_Copy}, 00355 {"CycleClip", F_CycleClip}, 00356 {"CycleCrosshair", F_CycleCrosshair}, 00357 {"DeleteRats", F_DeleteRats}, 00358 {"Drag", F_Drag}, 00359 {"DrillReport", F_DrillReport}, 00360 {"Element", F_Element}, 00361 {"ElementByName", F_ElementByName}, 00362 {"ElementConnections", F_ElementConnections}, 00363 {"ElementToBuffer", F_ElementToBuffer}, 00364 {"Escape", F_Escape}, 00365 {"Find", F_Find}, 00366 {"FlipElement", F_FlipElement}, 00367 {"FoundPins", F_FoundPins}, 00368 {"Grid", F_Grid}, 00369 {"InsertPoint", F_InsertPoint}, 00370 {"Layer", F_Layer}, 00371 {"Layout", F_Layout}, 00372 {"LayoutAs", F_LayoutAs}, 00373 {"LayoutToBuffer", F_LayoutToBuffer}, 00374 {"Line", F_Line}, 00375 {"LineSize", F_LineSize}, 00376 {"Lock", F_Lock}, 00377 {"Mirror", F_Mirror}, 00378 {"Move", F_Move}, 00379 {"NameOnPCB", F_NameOnPCB}, 00380 {"Netlist", F_Netlist}, 00381 {"NetByName", F_NetByName}, 00382 {"None", F_None}, 00383 {"Notify", F_Notify}, 00384 {"Object", F_Object}, 00385 {"ObjectByName", F_ObjectByName}, 00386 {"PasteBuffer", F_PasteBuffer}, 00387 {"PadByName", F_PadByName}, 00388 {"PinByName", F_PinByName}, 00389 {"PinOrPadName", F_PinOrPadName}, 00390 {"Pinout", F_Pinout}, 00391 {"Polygon", F_Polygon}, 00392 {"PolygonHole", F_PolygonHole}, 00393 {"PreviousPoint", F_PreviousPoint}, 00394 {"RatsNest", F_RatsNest}, 00395 {"Rectangle", F_Rectangle}, 00396 {"Redraw", F_Redraw}, 00397 {"Release", F_Release}, 00398 {"Remove", F_Remove}, 00399 {"RemoveSelected", F_RemoveSelected}, 00400 {"Report", F_Report}, 00401 {"Reset", F_Reset}, 00402 {"ResetLinesAndPolygons", F_ResetLinesAndPolygons}, 00403 {"ResetPinsViasAndPads", F_ResetPinsViasAndPads}, 00404 {"Restore", F_Restore}, 00405 {"Revert", F_Revert}, 00406 {"Rotate", F_Rotate}, 00407 {"Save", F_Save}, 00408 {"Selected", F_Selected}, 00409 {"SelectedArcs", F_SelectedArcs}, 00410 {"SelectedElements", F_SelectedElements}, 00411 {"SelectedLines", F_SelectedLines}, 00412 {"SelectedNames", F_SelectedNames}, 00413 {"SelectedObjects", F_SelectedObjects}, 00414 {"SelectedPins", F_SelectedPins}, 00415 {"SelectedPads", F_SelectedPads}, 00416 {"SelectedRats", F_SelectedRats}, 00417 {"SelectedTexts", F_SelectedTexts}, 00418 {"SelectedVias", F_SelectedVias}, 00419 {"Stroke", F_Stroke}, 00420 {"Text", F_Text}, 00421 {"TextByName", F_TextByName}, 00422 {"TextScale", F_TextScale}, 00423 {"Thermal", F_Thermal}, 00424 {"ToLayout", F_ToLayout}, 00425 {"Toggle45Degree", F_ToggleAllDirections}, 00426 {"ToggleClearLine", F_ToggleClearLine}, 00427 {"ToggleFullPoly", F_ToggleFullPoly}, 00428 {"ToggleGrid", F_ToggleGrid}, 00429 {"ToggleMask", F_ToggleMask}, 00430 {"ToggleName", F_ToggleName}, 00431 {"ToggleObject", F_ToggleObject}, 00432 {"ToggleRubberBandMode", F_ToggleRubberBandMode}, 00433 {"ToggleStartDirection", F_ToggleStartDirection}, 00434 {"ToggleSnapPin", F_ToggleSnapPin}, 00435 {"ToggleThindraw", F_ToggleThindraw}, 00436 {"ToggleThindrawPoly", F_ToggleThindrawPoly}, 00437 {"ToggleLockNames", F_ToggleLockNames}, 00438 {"ToggleOnlyNames", F_ToggleOnlyNames}, 00439 {"ToggleHideNames", F_ToggleHideNames}, 00440 {"ToggleCheckPlanes", F_ToggleCheckPlanes}, 00441 {"ToggleLocalRef", F_ToggleLocalRef}, 00442 {"ToggleOrthoMove", F_ToggleOrthoMove}, 00443 {"ToggleShowDRC", F_ToggleShowDRC}, 00444 {"ToggleLiveRoute", F_ToggleLiveRoute}, 00445 {"ToggleAutoDRC", F_ToggleAutoDRC}, 00446 {"ToggleUniqueNames", F_ToggleUniqueNames}, 00447 {"Value", F_Value}, 00448 {"Via", F_Via}, 00449 {"ViaByName", F_ViaByName}, 00450 {"ViaSize", F_ViaSize}, 00451 {"ViaDrillingHole", F_ViaDrillingHole}, 00452 {"Zoom", F_Zoom}, 00453 {"ThroughHole", F_ThroughHole}, 00454 {"TH", F_ThroughHole}, 00455 {"BuriedVias", F_BuriedVias}, 00456 {"ToggleAutoBuriedVias", F_ToggleAutoBuriedVias} 00457 }; 00458 00459 /* --------------------------------------------------------------------------- 00460 * some local routines 00461 */ 00462 static int GetFunctionID (String); 00463 static void AdjustAttachedBox (void); 00464 static void NotifyLine (void); 00465 static void NotifyBlock (void); 00466 static void NotifyMode (void); 00467 static void ClearWarnings (void); 00468 #ifdef HAVE_LIBSTROKE 00469 static void FinishStroke (void); 00470 extern void stroke_init (void); 00471 extern void stroke_record (int x, int y); 00472 extern int stroke_trans (char *s); 00473 #endif 00474 static void ChangeFlag (char *, char *, int, char *); 00475 00476 #define ARG(n) (argc > (n) ? argv[n] : NULL) 00477 00478 #ifdef HAVE_LIBSTROKE 00479 00483 void 00484 FinishStroke (void) 00485 { 00486 char msg[255]; 00487 int type; 00488 unsigned long num; 00489 void *ptr1, *ptr2, *ptr3; 00490 00491 mid_stroke = false; 00492 if (stroke_trans (msg)) 00493 { 00494 num = atoi (msg); 00495 switch (num) 00496 { 00497 case 456: 00498 if (Settings.Mode == LINE_MODE) 00499 { 00500 SetMode (LINE_MODE); 00501 } 00502 break; 00503 case 9874123: 00504 case 74123: 00505 case 987412: 00506 case 8741236: 00507 case 874123: 00508 RotateScreenObject (StrokeBox.X1, StrokeBox.Y1, SWAP_IDENT ? 1 : 3); 00509 break; 00510 case 7896321: 00511 case 786321: 00512 case 789632: 00513 case 896321: 00514 RotateScreenObject (StrokeBox.X1, StrokeBox.Y1, SWAP_IDENT ? 3 : 1); 00515 break; 00516 case 258: 00517 SetMode (LINE_MODE); 00518 break; 00519 case 852: 00520 SetMode (ARROW_MODE); 00521 break; 00522 case 1478963: 00523 ActionUndo (""); 00524 break; 00525 case 147423: 00526 case 147523: 00527 case 1474123: 00528 Redo (true); 00529 break; 00530 case 148963: 00531 case 147863: 00532 case 147853: 00533 case 145863: 00534 SetMode (VIA_MODE); 00535 break; 00536 case 951: 00537 case 9651: 00538 case 9521: 00539 case 9621: 00540 case 9851: 00541 case 9541: 00542 case 96521: 00543 case 96541: 00544 case 98541: 00545 /* XXX: FIXME: Call a zoom-extents action */ 00546 break; 00547 case 159: 00548 case 1269: 00549 case 1259: 00550 case 1459: 00551 case 1569: 00552 case 1589: 00553 case 12569: 00554 case 12589: 00555 case 14589: 00556 /* XXX: FIXME: Zoom to fit the box StrokeBox.[X1,Y1] - StrokeBox.[X2,Y2] */ 00557 break; 00558 00559 default: 00560 Message (_("Unknown stroke %s\n"), msg); 00561 break; 00562 } 00563 } 00564 else 00565 gui->beep (); 00566 } 00567 #endif 00568 00572 static void 00573 ClearWarnings () 00574 { 00575 Settings.RatWarn = false; 00576 ALLPIN_LOOP (PCB->Data); 00577 { 00578 if (TEST_FLAG (WARNFLAG, pin)) 00579 { 00580 CLEAR_FLAG (WARNFLAG, pin); 00581 DrawPin (pin); 00582 } 00583 } 00584 ENDALL_LOOP; 00585 ALLPAD_LOOP (PCB->Data); 00586 { 00587 if (TEST_FLAG (WARNFLAG, pad)) 00588 { 00589 CLEAR_FLAG (WARNFLAG, pad); 00590 DrawPad (pad); 00591 } 00592 } 00593 ENDALL_LOOP; 00594 Draw (); 00595 } 00596 00604 static void 00605 click_cb (hidval hv) 00606 { 00607 if (Note.Click) 00608 { 00609 notify_crosshair_change (false); 00610 Note.Click = false; 00611 if (Note.Moving && !gui->shift_is_pressed ()) 00612 { 00613 Note.Buffer = Settings.BufferNumber; 00614 SetBufferNumber (MAX_BUFFER - 1); 00615 ClearBuffer (PASTEBUFFER); 00616 AddSelectedToBuffer (PASTEBUFFER, Note.X, Note.Y, true); 00617 SaveUndoSerialNumber (); 00618 RemoveSelected (); 00619 SaveMode (); 00620 saved_mode = true; 00621 SetMode (PASTEBUFFER_MODE); 00622 } 00623 else if (Note.Hit && !gui->shift_is_pressed ()) 00624 { 00625 SaveMode (); 00626 saved_mode = true; 00627 SetMode (gui->control_is_pressed ()? COPY_MODE : MOVE_MODE); 00628 Crosshair.AttachedObject.Ptr1 = Note.ptr1; 00629 Crosshair.AttachedObject.Ptr2 = Note.ptr2; 00630 Crosshair.AttachedObject.Ptr3 = Note.ptr3; 00631 Crosshair.AttachedObject.Type = Note.Hit; 00632 AttachForCopy (Note.X, Note.Y); 00633 } 00634 else 00635 { 00636 BoxType box; 00637 00638 Note.Hit = 0; 00639 Note.Moving = false; 00640 SaveUndoSerialNumber (); 00641 box.X1 = -MAX_COORD; 00642 box.Y1 = -MAX_COORD; 00643 box.X2 = MAX_COORD; 00644 box.Y2 = MAX_COORD; 00645 /* unselect first if shift key not down */ 00646 if (!gui->shift_is_pressed () && SelectBlock (&box, false)) 00647 SetChangedFlag (true); 00648 NotifyBlock (); 00649 Crosshair.AttachedBox.Point1.X = Note.X; 00650 Crosshair.AttachedBox.Point1.Y = Note.Y; 00651 } 00652 notify_crosshair_change (true); 00653 } 00654 } 00655 00660 static void 00661 ReleaseMode (void) 00662 { 00663 BoxType box; 00664 00665 if (Note.Click) 00666 { 00667 BoxType box; 00668 00669 box.X1 = -MAX_COORD; 00670 box.Y1 = -MAX_COORD; 00671 box.X2 = MAX_COORD; 00672 box.Y2 = MAX_COORD; 00673 00674 Note.Click = false; /* inhibit timer action */ 00675 SaveUndoSerialNumber (); 00676 /* unselect first if shift key not down */ 00677 if (!gui->shift_is_pressed ()) 00678 { 00679 if (SelectBlock (&box, false)) 00680 SetChangedFlag (true); 00681 if (Note.Moving) 00682 { 00683 Note.Moving = 0; 00684 Note.Hit = 0; 00685 return; 00686 } 00687 } 00688 /* Restore the SN so that if we select something the deselect/select combo 00689 gets the same SN. */ 00690 RestoreUndoSerialNumber(); 00691 if (SelectObject ()) 00692 SetChangedFlag (true); 00693 else 00694 /* We didn't select anything new, so, the deselection should get its 00695 own SN. */ 00696 IncrementUndoSerialNumber(); 00697 Note.Hit = 0; 00698 Note.Moving = 0; 00699 } 00700 else if (Note.Moving) 00701 { 00702 RestoreUndoSerialNumber (); 00703 NotifyMode (); 00704 ClearBuffer (PASTEBUFFER); 00705 SetBufferNumber (Note.Buffer); 00706 Note.Moving = false; 00707 Note.Hit = 0; 00708 } 00709 else if (Note.Hit) 00710 { 00711 NotifyMode (); 00712 Note.Hit = 0; 00713 } 00714 else if (Settings.Mode == ARROW_MODE) 00715 { 00716 box.X1 = MIN (Crosshair.AttachedBox.Point1.X, 00717 Crosshair.AttachedBox.Point2.X); 00718 box.Y1 = MIN (Crosshair.AttachedBox.Point1.Y, 00719 Crosshair.AttachedBox.Point2.Y); 00720 box.X2 = MAX (Crosshair.AttachedBox.Point1.X, 00721 Crosshair.AttachedBox.Point2.X); 00722 box.Y2 = MAX (Crosshair.AttachedBox.Point1.Y, 00723 Crosshair.AttachedBox.Point2.Y); 00724 RestoreUndoSerialNumber (); 00725 if (SelectBlock (&box, true)) 00726 SetChangedFlag (true); 00727 else if (Bumped) 00728 IncrementUndoSerialNumber (); 00729 Crosshair.AttachedBox.State = STATE_FIRST; 00730 } 00731 if (saved_mode) 00732 RestoreMode (); 00733 saved_mode = false; 00734 } 00735 00736 #define HSIZE 257 00737 static char function_hash[HSIZE]; 00738 static int hash_initted = 0; 00739 00740 static int 00741 hashfunc(String s) 00742 { 00743 int i = 0; 00744 while (*s) 00745 { 00746 i ^= i >> 16; 00747 i = (i * 13) ^ (unsigned char)tolower((int) *s); 00748 s ++; 00749 } 00750 i = (unsigned int)i % HSIZE; 00751 return i; 00752 } 00753 00757 static int 00758 GetFunctionID (String Ident) 00759 { 00760 int i, h; 00761 00762 if (Ident == 0) 00763 return -1; 00764 00765 if (!hash_initted) 00766 { 00767 hash_initted = 1; 00768 if (HSIZE < ENTRIES (Functions) * 2) 00769 { 00770 fprintf(stderr, _("Error: function hash size too small (%d vs %lu at %s:%d)\n"), 00771 HSIZE, (unsigned long) ENTRIES (Functions)*2, __FILE__, __LINE__); 00772 exit(1); 00773 } 00774 if (ENTRIES (Functions) > 254) 00775 { 00776 /* Change 'char' to 'int' and remove this when we get to 256 00777 strings to hash. */ 00778 fprintf(stderr, _("Error: function hash type too small (%d vs %lu at %s:%d)\n"), 00779 256, (unsigned long) ENTRIES (Functions), __FILE__, __LINE__); 00780 exit(1); 00781 00782 } 00783 for (i=ENTRIES (Functions)-1; i>=0; i--) 00784 { 00785 h = hashfunc (Functions[i].Identifier); 00786 while (function_hash[h]) 00787 h = (h + 1) % HSIZE; 00788 function_hash[h] = i + 1; 00789 } 00790 } 00791 00792 i = hashfunc (Ident); 00793 while (1) 00794 { 00795 /* We enforce the "hash table bigger than function table" rule, 00796 so we know there will be at least one zero entry to find. */ 00797 if (!function_hash[i]) 00798 return (-1); 00799 if (!strcasecmp (Ident, Functions[function_hash[i]-1].Identifier)) 00800 return ((int) Functions[function_hash[i]-1].ID); 00801 i = (i + 1) % HSIZE; 00802 } 00803 } 00804 00810 static void 00811 AdjustAttachedBox (void) 00812 { 00813 if (Settings.Mode == ARC_MODE) 00814 { 00815 Crosshair.AttachedBox.otherway = gui->shift_is_pressed (); 00816 return; 00817 } 00818 switch (Crosshair.AttachedBox.State) 00819 { 00820 case STATE_SECOND: /* one corner is selected */ 00821 { 00822 /* update coordinates */ 00823 Crosshair.AttachedBox.Point2.X = Crosshair.X; 00824 Crosshair.AttachedBox.Point2.Y = Crosshair.Y; 00825 break; 00826 } 00827 } 00828 } 00829 00834 void 00835 AdjustAttachedObjects (void) 00836 { 00837 PointType *pnt; 00838 switch (Settings.Mode) 00839 { 00840 /* update at least an attached block (selection) */ 00841 case NO_MODE: 00842 case ARROW_MODE: 00843 if (Crosshair.AttachedBox.State) 00844 { 00845 Crosshair.AttachedBox.Point2.X = Crosshair.X; 00846 Crosshair.AttachedBox.Point2.Y = Crosshair.Y; 00847 } 00848 break; 00849 00850 /* rectangle creation mode */ 00851 case RECTANGLE_MODE: 00852 case ARC_MODE: 00853 AdjustAttachedBox (); 00854 break; 00855 00856 /* polygon creation mode */ 00857 case POLYGON_MODE: 00858 case POLYGONHOLE_MODE: 00859 AdjustAttachedLine (); 00860 break; 00861 /* line creation mode */ 00862 case LINE_MODE: 00863 if (PCB->RatDraw || PCB->Clipping == 0) 00864 AdjustAttachedLine (); 00865 else 00866 AdjustTwoLine (PCB->Clipping - 1); 00867 break; 00868 /* point insertion mode */ 00869 case INSERTPOINT_MODE: 00870 pnt = AdjustInsertPoint (); 00871 if (pnt) 00872 InsertedPoint = *pnt; 00873 break; 00874 case ROTATE_MODE: 00875 break; 00876 } 00877 } 00878 00882 static void 00883 NotifyLine (void) 00884 { 00885 int type = NO_TYPE; 00886 void *ptr1, *ptr2, *ptr3; 00887 00888 if (!Marked.status || TEST_FLAG (LOCALREFFLAG, PCB)) 00889 SetLocalRef (Crosshair.X, Crosshair.Y, true); 00890 switch (Crosshair.AttachedLine.State) 00891 { 00892 case STATE_FIRST: /* first point */ 00893 if (PCB->RatDraw && SearchScreen (Crosshair.X, Crosshair.Y, 00894 PAD_TYPE | PIN_TYPE, &ptr1, &ptr1, 00895 &ptr1) == NO_TYPE) 00896 { 00897 gui->beep (); 00898 break; 00899 } 00900 if (TEST_FLAG (AUTODRCFLAG, PCB) && Settings.Mode == LINE_MODE) 00901 { 00902 type = SearchScreen (Crosshair.X, Crosshair.Y, 00903 PIN_TYPE | PAD_TYPE | VIA_TYPE, &ptr1, &ptr2, 00904 &ptr3); 00905 LookupConnection (Crosshair.X, Crosshair.Y, true, 1, CONNECTEDFLAG, false); 00906 LookupConnection (Crosshair.X, Crosshair.Y, true, 1, FOUNDFLAG, true); 00907 } 00908 if (type == PIN_TYPE || type == VIA_TYPE) 00909 { 00910 Crosshair.AttachedLine.Point1.X = 00911 Crosshair.AttachedLine.Point2.X = ((PinType *) ptr2)->X; 00912 Crosshair.AttachedLine.Point1.Y = 00913 Crosshair.AttachedLine.Point2.Y = ((PinType *) ptr2)->Y; 00914 } 00915 else if (type == PAD_TYPE) 00916 { 00917 PadType *pad = (PadType *) ptr2; 00918 double d1 = Distance (Crosshair.X, Crosshair.Y, pad->Point1.X, pad->Point1.Y); 00919 double d2 = Distance (Crosshair.X, Crosshair.Y, pad->Point2.X, pad->Point2.Y); 00920 if (d2 < d1) 00921 { 00922 Crosshair.AttachedLine.Point1 = 00923 Crosshair.AttachedLine.Point2 = pad->Point2; 00924 } 00925 else 00926 { 00927 Crosshair.AttachedLine.Point1 = 00928 Crosshair.AttachedLine.Point2 = pad->Point1; 00929 } 00930 } 00931 else 00932 { 00933 Crosshair.AttachedLine.Point1.X = 00934 Crosshair.AttachedLine.Point2.X = Crosshair.X; 00935 Crosshair.AttachedLine.Point1.Y = 00936 Crosshair.AttachedLine.Point2.Y = Crosshair.Y; 00937 } 00938 Crosshair.AttachedLine.State = STATE_SECOND; 00939 break; 00940 00941 case STATE_SECOND: 00942 /* fall through to third state too */ 00943 lastLayer = CURRENT; 00944 default: /* all following points */ 00945 Crosshair.AttachedLine.State = STATE_THIRD; 00946 break; 00947 } 00948 } 00949 00953 static void 00954 NotifyBlock (void) 00955 { 00956 notify_crosshair_change (false); 00957 switch (Crosshair.AttachedBox.State) 00958 { 00959 case STATE_FIRST: /* setup first point */ 00960 Crosshair.AttachedBox.Point1.X = 00961 Crosshair.AttachedBox.Point2.X = Crosshair.X; 00962 Crosshair.AttachedBox.Point1.Y = 00963 Crosshair.AttachedBox.Point2.Y = Crosshair.Y; 00964 Crosshair.AttachedBox.State = STATE_SECOND; 00965 break; 00966 00967 case STATE_SECOND: /* setup second point */ 00968 Crosshair.AttachedBox.State = STATE_THIRD; 00969 break; 00970 } 00971 notify_crosshair_change (true); 00972 } 00973 00974 00985 static void 00986 NotifyMode (void) 00987 { 00988 void *ptr1, *ptr2, *ptr3; 00989 int type; 00990 00991 if (Settings.RatWarn) 00992 ClearWarnings (); 00993 switch (Settings.Mode) 00994 { 00995 case ARROW_MODE: 00996 { 00997 int test; 00998 hidval hv; 00999 01000 Note.Click = true; 01001 /* do something after click time */ 01002 gui->add_timer (click_cb, CLICK_TIME, hv); 01003 01004 /* see if we clicked on something already selected 01005 * (Note.Moving) or clicked on a MOVE_TYPE 01006 * (Note.Hit) 01007 */ 01008 for (test = (SELECT_TYPES | MOVE_TYPES) & ~RATLINE_TYPE; 01009 test; test &= ~type) 01010 { 01011 type = SearchScreen (Note.X, Note.Y, test, &ptr1, &ptr2, &ptr3); 01012 if (!Note.Hit && (type & MOVE_TYPES) && 01013 !TEST_FLAG (LOCKFLAG, (PinType *) ptr2)) 01014 { 01015 Note.Hit = type; 01016 Note.ptr1 = ptr1; 01017 Note.ptr2 = ptr2; 01018 Note.ptr3 = ptr3; 01019 } 01020 if (!Note.Moving && (type & SELECT_TYPES) && 01021 TEST_FLAG (SELECTEDFLAG, (PinType *) ptr2)) 01022 Note.Moving = true; 01023 if ((Note.Hit && Note.Moving) || type == NO_TYPE) 01024 break; 01025 } 01026 break; 01027 } 01028 01029 case VIA_MODE: 01030 { 01031 PinType *via; 01032 01033 if (!PCB->ViaOn) 01034 { 01035 Message (_("You must turn via visibility on before\n" 01036 "you can place vias\n")); 01037 break; 01038 } 01039 if ((via = CreateNewVia (PCB->Data, Note.X, Note.Y, 01040 Settings.ViaThickness, 2 * Settings.Keepaway, 01041 0, Settings.ViaDrillingHole, NULL, 01042 NoFlags ())) != NULL) 01043 { 01044 AddObjectToCreateUndoList (VIA_TYPE, via, via, via); 01045 if (gui->shift_is_pressed ()) 01046 ChangeObjectThermal (VIA_TYPE, via, via, via, PCB->ThermStyle); 01047 IncrementUndoSerialNumber (); 01048 DrawVia (via); 01049 Draw (); 01050 } 01051 break; 01052 } 01053 01054 case ARC_MODE: 01055 { 01056 switch (Crosshair.AttachedBox.State) 01057 { 01058 case STATE_FIRST: 01059 Crosshair.AttachedBox.Point1.X = 01060 Crosshair.AttachedBox.Point2.X = Note.X; 01061 Crosshair.AttachedBox.Point1.Y = 01062 Crosshair.AttachedBox.Point2.Y = Note.Y; 01063 Crosshair.AttachedBox.State = STATE_SECOND; 01064 break; 01065 01066 case STATE_SECOND: 01067 case STATE_THIRD: 01068 { 01069 ArcType *arc; 01070 Coord wx, wy; 01071 Angle sa, dir; 01072 01073 wx = Note.X - Crosshair.AttachedBox.Point1.X; 01074 wy = Note.Y - Crosshair.AttachedBox.Point1.Y; 01075 if (XOR (Crosshair.AttachedBox.otherway, abs (wy) > abs (wx))) 01076 { 01077 Crosshair.AttachedBox.Point2.X = 01078 Crosshair.AttachedBox.Point1.X + abs (wy) * SGNZ (wx); 01079 sa = (wx >= 0) ? 0 : 180; 01080 #ifdef ARC45 01081 if (abs (wy) / 2 >= abs (wx)) 01082 dir = (SGNZ (wx) == SGNZ (wy)) ? 45 : -45; 01083 else 01084 #endif 01085 dir = (SGNZ (wx) == SGNZ (wy)) ? 90 : -90; 01086 } 01087 else 01088 { 01089 Crosshair.AttachedBox.Point2.Y = 01090 Crosshair.AttachedBox.Point1.Y + abs (wx) * SGNZ (wy); 01091 sa = (wy >= 0) ? -90 : 90; 01092 #ifdef ARC45 01093 if (abs (wx) / 2 >= abs (wy)) 01094 dir = (SGNZ (wx) == SGNZ (wy)) ? -45 : 45; 01095 else 01096 #endif 01097 dir = (SGNZ (wx) == SGNZ (wy)) ? -90 : 90; 01098 wy = wx; 01099 } 01100 if (abs (wy) > 0 && (arc = CreateNewArcOnLayer (CURRENT, 01101 Crosshair. 01102 AttachedBox. 01103 Point2.X, 01104 Crosshair. 01105 AttachedBox. 01106 Point2.Y, 01107 abs (wy), 01108 abs (wy), 01109 sa, 01110 dir, 01111 Settings. 01112 LineThickness, 01113 2 * Settings. 01114 Keepaway, 01115 MakeFlags 01116 (TEST_FLAG 01117 (CLEARNEWFLAG, 01118 PCB) ? 01119 CLEARLINEFLAG : 01120 0)))) 01121 { 01122 BoxType *bx; 01123 01124 bx = GetArcEnds (arc); 01125 Crosshair.AttachedBox.Point1.X = 01126 Crosshair.AttachedBox.Point2.X = bx->X2; 01127 Crosshair.AttachedBox.Point1.Y = 01128 Crosshair.AttachedBox.Point2.Y = bx->Y2; 01129 AddObjectToCreateUndoList (ARC_TYPE, CURRENT, arc, arc); 01130 IncrementUndoSerialNumber (); 01131 addedLines++; 01132 DrawArc (CURRENT, arc); 01133 Draw (); 01134 Crosshair.AttachedBox.State = STATE_THIRD; 01135 } 01136 break; 01137 } 01138 } 01139 break; 01140 } 01141 case LOCK_MODE: 01142 { 01143 type = SearchScreen (Note.X, Note.Y, LOCK_TYPES, &ptr1, &ptr2, &ptr3); 01144 if (type == ELEMENT_TYPE) 01145 { 01146 ElementType *element = (ElementType *) ptr2; 01147 01148 TOGGLE_FLAG (LOCKFLAG, element); 01149 PIN_LOOP (element); 01150 { 01151 TOGGLE_FLAG (LOCKFLAG, pin); 01152 CLEAR_FLAG (SELECTEDFLAG, pin); 01153 } 01154 END_LOOP; 01155 PAD_LOOP (element); 01156 { 01157 TOGGLE_FLAG (LOCKFLAG, pad); 01158 CLEAR_FLAG (SELECTEDFLAG, pad); 01159 } 01160 END_LOOP; 01161 CLEAR_FLAG (SELECTEDFLAG, element); 01162 /* always re-draw it since I'm too lazy 01163 * to tell if a selected flag changed 01164 */ 01165 DrawElement (element); 01166 Draw (); 01167 SetChangedFlag (true); 01168 hid_actionl ("Report", "Object", NULL); 01169 } 01170 else if (type != NO_TYPE) 01171 { 01172 TextType *thing = (TextType *) ptr3; 01173 TOGGLE_FLAG (LOCKFLAG, thing); 01174 if (TEST_FLAG (LOCKFLAG, thing) 01175 && TEST_FLAG (SELECTEDFLAG, thing)) 01176 { 01177 /* this is not un-doable since LOCK isn't */ 01178 CLEAR_FLAG (SELECTEDFLAG, thing); 01179 DrawObject (type, ptr1, ptr2); 01180 Draw (); 01181 } 01182 SetChangedFlag (true); 01183 hid_actionl ("Report", "Object", NULL); 01184 } 01185 break; 01186 } 01187 case THERMAL_MODE: 01188 { 01189 if (((type 01190 = 01191 SearchScreen (Note.X, Note.Y, PIN_TYPES, &ptr1, &ptr2, 01192 &ptr3)) != NO_TYPE) 01193 && !TEST_FLAG (HOLEFLAG, (PinType *) ptr3)) 01194 { 01195 if (gui->shift_is_pressed ()) 01196 { 01197 int tstyle = GET_THERM (INDEXOFCURRENT, (PinType *) ptr3); 01198 tstyle++; 01199 if (tstyle > 5) 01200 tstyle = 1; 01201 ChangeObjectThermal (type, ptr1, ptr2, ptr3, tstyle); 01202 } 01203 else if (GET_THERM (INDEXOFCURRENT, (PinType *) ptr3)) 01204 ChangeObjectThermal (type, ptr1, ptr2, ptr3, 0); 01205 else 01206 ChangeObjectThermal (type, ptr1, ptr2, ptr3, PCB->ThermStyle); 01207 } 01208 break; 01209 } 01210 01211 case LINE_MODE: 01212 /* do update of position */ 01213 NotifyLine (); 01214 if (Crosshair.AttachedLine.State != STATE_THIRD) 01215 break; 01216 01217 /* Remove anchor if clicking on start point; 01218 * this means we can't paint 0 length lines 01219 * which could be used for square SMD pads. 01220 * Instead use a very small delta, or change 01221 * the file after saving. 01222 */ 01223 if (Crosshair.X == Crosshair.AttachedLine.Point1.X 01224 && Crosshair.Y == Crosshair.AttachedLine.Point1.Y) 01225 { 01226 SetMode (LINE_MODE); 01227 break; 01228 } 01229 01230 if (PCB->RatDraw) 01231 { 01232 RatType *line; 01233 if ((line = AddNet ())) 01234 { 01235 addedLines++; 01236 AddObjectToCreateUndoList (RATLINE_TYPE, line, line, line); 01237 IncrementUndoSerialNumber (); 01238 DrawRat (line); 01239 Crosshair.AttachedLine.Point1.X = 01240 Crosshair.AttachedLine.Point2.X; 01241 Crosshair.AttachedLine.Point1.Y = 01242 Crosshair.AttachedLine.Point2.Y; 01243 Draw (); 01244 } 01245 break; 01246 } 01247 else 01248 /* create line if both ends are determined && length != 0 */ 01249 { 01250 LineType *line; 01251 int line_flags = 0; 01252 01253 if (TEST_FLAG (AUTODRCFLAG, PCB) && !TEST_SILK_LAYER (CURRENT)) 01254 line_flags |= CONNECTEDFLAG | FOUNDFLAG; 01255 01256 if (TEST_FLAG (CLEARNEWFLAG, PCB)) 01257 line_flags |= CLEARLINEFLAG; 01258 01259 if (PCB->Clipping 01260 && Crosshair.AttachedLine.Point1.X == 01261 Crosshair.AttachedLine.Point2.X 01262 && Crosshair.AttachedLine.Point1.Y == 01263 Crosshair.AttachedLine.Point2.Y 01264 && (Crosshair.AttachedLine.Point2.X != Note.X 01265 || Crosshair.AttachedLine.Point2.Y != Note.Y)) 01266 { 01267 /* We will only need to paint the second line segment. 01268 Since we only check for vias on the first segment, 01269 swap them so the non-empty segment is the first segment. */ 01270 Crosshair.AttachedLine.Point2.X = Note.X; 01271 Crosshair.AttachedLine.Point2.Y = Note.Y; 01272 } 01273 01274 if ((Crosshair.AttachedLine.Point1.X != 01275 Crosshair.AttachedLine.Point2.X 01276 || Crosshair.AttachedLine.Point1.Y != 01277 Crosshair.AttachedLine.Point2.Y)) 01278 { 01279 PinType *via; 01280 Cardinal layer_from, layer_to; 01281 01282 if ((line = 01283 CreateDrawnLineOnLayer (CURRENT, 01284 Crosshair.AttachedLine.Point1.X, 01285 Crosshair.AttachedLine.Point1.Y, 01286 Crosshair.AttachedLine.Point2.X, 01287 Crosshair.AttachedLine.Point2.Y, 01288 Settings.LineThickness, 01289 2 * Settings.Keepaway, 01290 MakeFlags (line_flags))) != NULL) 01291 { 01292 addedLines++; 01293 AddObjectToCreateUndoList (LINE_TYPE, CURRENT, line, line); 01294 DrawLine (CURRENT, line); 01295 } 01296 /* place a via if vias are visible, the layer is 01297 in a new group since the last line and there 01298 isn't a pin already here */ 01299 if (TEST_FLAG (AUTOBURIEDVIASFLAG, PCB)) 01300 { 01301 layer_from = GetLayerNumber (PCB->Data, lastLayer); 01302 layer_to = GetLayerNumber (PCB->Data, CURRENT); 01303 } 01304 else 01305 { 01306 layer_from = 0; 01307 layer_to = 0; 01308 } 01309 01310 if (PCB->ViaOn && GetLayerGroupNumberByPointer (CURRENT) != 01311 GetLayerGroupNumberByPointer (lastLayer) && 01312 SearchObjectByLocation (PIN_TYPES, &ptr1, &ptr2, &ptr3, 01313 Crosshair.AttachedLine.Point1.X, 01314 Crosshair.AttachedLine.Point1.Y, 01315 Settings.ViaThickness / 2) == 01316 NO_TYPE 01317 && (via = 01318 CreateNewViaEx (PCB->Data, 01319 Crosshair.AttachedLine.Point1.X, 01320 Crosshair.AttachedLine.Point1.Y, 01321 Settings.ViaThickness, 01322 2 * Settings.Keepaway, 0, 01323 Settings.ViaDrillingHole, NULL, 01324 NoFlags (), layer_from, layer_to)) != NULL) 01325 { 01326 AddObjectToCreateUndoList (VIA_TYPE, via, via, via); 01327 DrawVia (via); 01328 } 01329 /* copy the coordinates */ 01330 Crosshair.AttachedLine.Point1.X = 01331 Crosshair.AttachedLine.Point2.X; 01332 Crosshair.AttachedLine.Point1.Y = 01333 Crosshair.AttachedLine.Point2.Y; 01334 IncrementUndoSerialNumber (); 01335 lastLayer = CURRENT; 01336 } 01337 if (PCB->Clipping && (Note.X != Crosshair.AttachedLine.Point2.X 01338 || Note.Y != 01339 Crosshair.AttachedLine.Point2.Y)) 01340 { 01341 if ((line = 01342 CreateDrawnLineOnLayer (CURRENT, 01343 Crosshair.AttachedLine.Point2.X, 01344 Crosshair.AttachedLine.Point2.Y, 01345 Note.X, Note.Y, 01346 Settings.LineThickness, 01347 2 * Settings.Keepaway, 01348 MakeFlags (line_flags))) != NULL) 01349 { 01350 addedLines++; 01351 AddObjectToCreateUndoList (LINE_TYPE, CURRENT, line, line); 01352 IncrementUndoSerialNumber (); 01353 DrawLine (CURRENT, line); 01354 } 01355 /* move to new start point */ 01356 Crosshair.AttachedLine.Point1.X = Note.X; 01357 Crosshair.AttachedLine.Point1.Y = Note.Y; 01358 Crosshair.AttachedLine.Point2.X = Note.X; 01359 Crosshair.AttachedLine.Point2.Y = Note.Y; 01360 if (TEST_FLAG (SWAPSTARTDIRFLAG, PCB)) 01361 { 01362 PCB->Clipping ^= 3; 01363 } 01364 } 01365 if (TEST_FLAG (AUTODRCFLAG, PCB) && !TEST_SILK_LAYER (CURRENT)) 01366 LookupConnection (Note.X, Note.Y, true, 1, CONNECTEDFLAG, false); 01367 Draw (); 01368 } 01369 break; 01370 01371 case RECTANGLE_MODE: 01372 /* do update of position */ 01373 NotifyBlock (); 01374 01375 /* create rectangle if both corners are determined 01376 * and width, height are != 0 01377 */ 01378 if (Crosshair.AttachedBox.State == STATE_THIRD && 01379 Crosshair.AttachedBox.Point1.X != Crosshair.AttachedBox.Point2.X && 01380 Crosshair.AttachedBox.Point1.Y != Crosshair.AttachedBox.Point2.Y) 01381 { 01382 PolygonType *polygon; 01383 01384 int flags = CLEARPOLYFLAG; 01385 if (TEST_FLAG (NEWFULLPOLYFLAG, PCB)) 01386 flags |= FULLPOLYFLAG; 01387 if ((polygon = CreateNewPolygonFromRectangle (CURRENT, 01388 Crosshair. 01389 AttachedBox.Point1.X, 01390 Crosshair. 01391 AttachedBox.Point1.Y, 01392 Crosshair. 01393 AttachedBox.Point2.X, 01394 Crosshair. 01395 AttachedBox.Point2.Y, 01396 MakeFlags 01397 (flags))) != 01398 NULL) 01399 { 01400 AddObjectToCreateUndoList (POLYGON_TYPE, CURRENT, 01401 polygon, polygon); 01402 IncrementUndoSerialNumber (); 01403 DrawPolygon (CURRENT, polygon); 01404 Draw (); 01405 } 01406 01407 /* reset state to 'first corner' */ 01408 Crosshair.AttachedBox.State = STATE_FIRST; 01409 } 01410 break; 01411 01412 case TEXT_MODE: 01413 { 01414 char *string; 01415 01416 if ((string = gui->prompt_for (_("Enter text:"), "")) != NULL) 01417 { 01418 if (strlen(string) > 0) 01419 { 01420 TextType *text; 01421 int flag = CLEARLINEFLAG; 01422 01423 if (GetLayerGroupNumberByNumber (INDEXOFCURRENT) == 01424 GetLayerGroupNumberBySide (BOTTOM_SIDE)) 01425 flag |= ONSOLDERFLAG; 01426 if ((text = CreateNewText (CURRENT, &PCB->Font, Note.X, 01427 Note.Y, 0, Settings.TextScale, 01428 string, MakeFlags (flag))) != NULL) 01429 { 01430 AddObjectToCreateUndoList (TEXT_TYPE, CURRENT, text, text); 01431 IncrementUndoSerialNumber (); 01432 DrawText (CURRENT, text); 01433 Draw (); 01434 } 01435 } 01436 free (string); 01437 } 01438 break; 01439 } 01440 01441 case POLYGON_MODE: 01442 { 01443 PointType *points = Crosshair.AttachedPolygon.Points; 01444 Cardinal n = Crosshair.AttachedPolygon.PointN; 01445 01446 /* do update of position; use the 'LINE_MODE' mechanism */ 01447 NotifyLine (); 01448 01449 /* check if this is the last point of a polygon */ 01450 if (n >= 3 && 01451 points->X == Crosshair.AttachedLine.Point2.X && 01452 points->Y == Crosshair.AttachedLine.Point2.Y) 01453 { 01454 CopyAttachedPolygonToLayer (); 01455 Draw (); 01456 break; 01457 } 01458 01459 /* create new point if it's the first one or if it's 01460 * different to the last one 01461 */ 01462 if (!n || 01463 points[n - 1].X != Crosshair.AttachedLine.Point2.X || 01464 points[n - 1].Y != Crosshair.AttachedLine.Point2.Y) 01465 { 01466 CreateNewPointInPolygon (&Crosshair.AttachedPolygon, 01467 Crosshair.AttachedLine.Point2.X, 01468 Crosshair.AttachedLine.Point2.Y); 01469 01470 /* copy the coordinates */ 01471 Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X; 01472 Crosshair.AttachedLine.Point1.Y = Crosshair.AttachedLine.Point2.Y; 01473 } 01474 break; 01475 } 01476 01477 case POLYGONHOLE_MODE: 01478 { 01479 switch (Crosshair.AttachedObject.State) 01480 { 01481 /* first notify, lookup object */ 01482 case STATE_FIRST: 01483 Crosshair.AttachedObject.Type = 01484 SearchScreen (Note.X, Note.Y, POLYGON_TYPE, 01485 &Crosshair.AttachedObject.Ptr1, 01486 &Crosshair.AttachedObject.Ptr2, 01487 &Crosshair.AttachedObject.Ptr3); 01488 01489 if (Crosshair.AttachedObject.Type == NO_TYPE) 01490 { 01491 Message (_("The first point of a polygon hole must be on a polygon.\n")); 01492 break; /* don't start doing anything if clicked outside of polys */ 01493 } 01494 01495 if (TEST_FLAG(LOCKFLAG, (PolygonType *) Crosshair.AttachedObject.Ptr2)) 01496 { 01497 Message (_("Sorry, the object is locked\n")); 01498 Crosshair.AttachedObject.Type = NO_TYPE; 01499 break; 01500 } 01501 else 01502 Crosshair.AttachedObject.State = STATE_SECOND; 01503 /* Fall thru: first click is also the first point of the 01504 * poly hole. */ 01505 01506 /* second notify, insert new point into object */ 01507 case STATE_SECOND: 01508 { 01509 PointType *points = Crosshair.AttachedPolygon.Points; 01510 Cardinal n = Crosshair.AttachedPolygon.PointN; 01511 POLYAREA *original, *new_hole, *result; 01512 FlagType Flags; 01513 01514 /* do update of position; use the 'LINE_MODE' mechanism */ 01515 NotifyLine (); 01516 01517 /* check if this is the last point of a polygon */ 01518 if (n >= 3 && 01519 points->X == Crosshair.AttachedLine.Point2.X && 01520 points->Y == Crosshair.AttachedLine.Point2.Y) 01521 { 01522 /* Create POLYAREAs from the original polygon 01523 * and the new hole polygon */ 01524 original = PolygonToPoly ((PolygonType *)Crosshair.AttachedObject.Ptr2); 01525 new_hole = PolygonToPoly (&Crosshair.AttachedPolygon); 01526 01527 /* Subtract the hole from the original polygon shape */ 01528 poly_Boolean_free (original, new_hole, &result, PBO_SUB); 01529 01530 /* Convert the resulting polygon(s) into a new set of nodes 01531 * and place them on the page. Delete the original polygon. 01532 */ 01533 SaveUndoSerialNumber (); 01534 Flags = ((PolygonType *)Crosshair.AttachedObject.Ptr2)->Flags; 01535 PolyToPolygonsOnLayer (PCB->Data, (LayerType *)Crosshair.AttachedObject.Ptr1, 01536 result, Flags); 01537 RemoveObject (POLYGON_TYPE, 01538 Crosshair.AttachedObject.Ptr1, 01539 Crosshair.AttachedObject.Ptr2, 01540 Crosshair.AttachedObject.Ptr3); 01541 RestoreUndoSerialNumber (); 01542 IncrementUndoSerialNumber (); 01543 Draw (); 01544 01545 /* reset state of attached line */ 01546 memset (&Crosshair.AttachedPolygon, 0, sizeof (PolygonType)); 01547 Crosshair.AttachedObject.State = STATE_FIRST; 01548 addedLines = 0; 01549 01550 break; 01551 } 01552 01553 /* create new point if it's the first one or if it's 01554 * different to the last one 01555 */ 01556 if (!n || 01557 points[n - 1].X != Crosshair.AttachedLine.Point2.X || 01558 points[n - 1].Y != Crosshair.AttachedLine.Point2.Y) 01559 { 01560 CreateNewPointInPolygon (&Crosshair.AttachedPolygon, 01561 Crosshair.AttachedLine.Point2.X, 01562 Crosshair.AttachedLine.Point2.Y); 01563 01564 /* copy the coordinates */ 01565 Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X; 01566 Crosshair.AttachedLine.Point1.Y = Crosshair.AttachedLine.Point2.Y; 01567 } 01568 break; 01569 } 01570 } 01571 01572 break; 01573 } 01574 01575 case PASTEBUFFER_MODE: 01576 { 01577 TextType estr[MAX_ELEMENTNAMES]; 01578 ElementType *e = 0; 01579 01580 if (gui->shift_is_pressed ()) 01581 { 01582 int type = 01583 SearchScreen (Note.X, Note.Y, ELEMENT_TYPE, &ptr1, &ptr2, 01584 &ptr3); 01585 if (type == ELEMENT_TYPE) 01586 { 01587 e = (ElementType *) ptr1; 01588 if (e) 01589 { 01590 int i; 01591 01592 memcpy (estr, e->Name, 01593 MAX_ELEMENTNAMES * sizeof (TextType)); 01594 for (i = 0; i < MAX_ELEMENTNAMES; ++i) 01595 estr[i].TextString = estr[i].TextString ? strdup(estr[i].TextString) : NULL; 01596 RemoveElement (e); 01597 } 01598 } 01599 } 01600 if (CopyPastebufferToLayout (Note.X, Note.Y)) 01601 SetChangedFlag (true); 01602 if (e) 01603 { 01604 int type = 01605 SearchScreen (Note.X, Note.Y, ELEMENT_TYPE, &ptr1, &ptr2, 01606 &ptr3); 01607 if (type == ELEMENT_TYPE && ptr1) 01608 { 01609 int i, save_n; 01610 e = (ElementType *) ptr1; 01611 01612 save_n = NAME_INDEX (PCB); 01613 01614 for (i = 0; i < MAX_ELEMENTNAMES; i++) 01615 { 01616 if (i == save_n) 01617 EraseElementName (e); 01618 r_delete_entry (PCB->Data->name_tree[i], 01619 (BoxType *) & (e->Name[i])); 01620 memcpy (&(e->Name[i]), &(estr[i]), sizeof (TextType)); 01621 e->Name[i].Element = e; 01622 SetTextBoundingBox (&PCB->Font, &(e->Name[i])); 01623 r_insert_entry (PCB->Data->name_tree[i], 01624 (BoxType *) & (e->Name[i]), 0); 01625 if (i == save_n) 01626 DrawElementName (e); 01627 } 01628 } 01629 } 01630 break; 01631 } 01632 01633 case REMOVE_MODE: 01634 if ((type = 01635 SearchScreen (Note.X, Note.Y, REMOVE_TYPES, &ptr1, &ptr2, 01636 &ptr3)) != NO_TYPE) 01637 { 01638 if (TEST_FLAG (LOCKFLAG, (LineType *) ptr2)) 01639 { 01640 Message (_("Sorry, the object is locked\n")); 01641 break; 01642 } 01643 if (type == ELEMENT_TYPE) 01644 { 01645 RubberbandType *ptr; 01646 int i; 01647 01648 Crosshair.AttachedObject.RubberbandN = 0; 01649 LookupRatLines (type, ptr1, ptr2, ptr3); 01650 ptr = Crosshair.AttachedObject.Rubberband; 01651 for (i = 0; i < Crosshair.AttachedObject.RubberbandN; i++) 01652 { 01653 if (PCB->RatOn) 01654 EraseRat ((RatType *) ptr->Line); 01655 if (TEST_FLAG (RUBBERENDFLAG, ptr->Line)) 01656 MoveObjectToRemoveUndoList (RATLINE_TYPE, 01657 ptr->Line, ptr->Line, 01658 ptr->Line); 01659 else 01660 TOGGLE_FLAG (RUBBERENDFLAG, ptr->Line); /* only remove line once */ 01661 ptr++; 01662 } 01663 } 01664 RemoveObject (type, ptr1, ptr2, ptr3); 01665 IncrementUndoSerialNumber (); 01666 SetChangedFlag (true); 01667 } 01668 break; 01669 01670 case ROTATE_MODE: 01671 RotateScreenObject (Note.X, Note.Y, 01672 gui->shift_is_pressed ()? (SWAP_IDENT ? 01673 1 : 3) 01674 : (SWAP_IDENT ? 3 : 1)); 01675 break; 01676 01677 /* both are almost the same */ 01678 case COPY_MODE: 01679 case MOVE_MODE: 01680 switch (Crosshair.AttachedObject.State) 01681 { 01682 /* first notify, lookup object */ 01683 case STATE_FIRST: 01684 { 01685 int types = (Settings.Mode == COPY_MODE) ? 01686 COPY_TYPES : MOVE_TYPES; 01687 01688 Crosshair.AttachedObject.Type = 01689 SearchScreen (Note.X, Note.Y, types, 01690 &Crosshair.AttachedObject.Ptr1, 01691 &Crosshair.AttachedObject.Ptr2, 01692 &Crosshair.AttachedObject.Ptr3); 01693 if (Crosshair.AttachedObject.Type != NO_TYPE) 01694 { 01695 if (Settings.Mode == MOVE_MODE && 01696 TEST_FLAG (LOCKFLAG, (PinType *) 01697 Crosshair.AttachedObject.Ptr2)) 01698 { 01699 Message (_("Sorry, the object is locked\n")); 01700 Crosshair.AttachedObject.Type = NO_TYPE; 01701 } 01702 else 01703 AttachForCopy (Note.X, Note.Y); 01704 } 01705 break; 01706 } 01707 01708 /* second notify, move or copy object */ 01709 case STATE_SECOND: 01710 if (Settings.Mode == COPY_MODE) 01711 CopyObject (Crosshair.AttachedObject.Type, 01712 Crosshair.AttachedObject.Ptr1, 01713 Crosshair.AttachedObject.Ptr2, 01714 Crosshair.AttachedObject.Ptr3, 01715 Note.X - Crosshair.AttachedObject.X, 01716 Note.Y - Crosshair.AttachedObject.Y); 01717 else 01718 { 01719 MoveObjectAndRubberband (Crosshair.AttachedObject.Type, 01720 Crosshair.AttachedObject.Ptr1, 01721 Crosshair.AttachedObject.Ptr2, 01722 Crosshair.AttachedObject.Ptr3, 01723 Note.X - Crosshair.AttachedObject.X, 01724 Note.Y - Crosshair.AttachedObject.Y); 01725 SetLocalRef (0, 0, false); 01726 } 01727 SetChangedFlag (true); 01728 01729 /* reset identifiers */ 01730 Crosshair.AttachedObject.Type = NO_TYPE; 01731 Crosshair.AttachedObject.State = STATE_FIRST; 01732 break; 01733 } 01734 break; 01735 01736 /* insert a point into a polygon/line/... */ 01737 case INSERTPOINT_MODE: 01738 switch (Crosshair.AttachedObject.State) 01739 { 01740 /* first notify, lookup object */ 01741 case STATE_FIRST: 01742 Crosshair.AttachedObject.Type = 01743 SearchScreen (Note.X, Note.Y, INSERT_TYPES, 01744 &Crosshair.AttachedObject.Ptr1, 01745 &Crosshair.AttachedObject.Ptr2, 01746 &Crosshair.AttachedObject.Ptr3); 01747 01748 if (Crosshair.AttachedObject.Type != NO_TYPE) 01749 { 01750 if (TEST_FLAG (LOCKFLAG, (PolygonType *) 01751 Crosshair.AttachedObject.Ptr2)) 01752 { 01753 Message (_("Sorry, the object is locked\n")); 01754 Crosshair.AttachedObject.Type = NO_TYPE; 01755 break; 01756 } 01757 else 01758 { 01759 /* get starting point of nearest segment */ 01760 if (Crosshair.AttachedObject.Type == POLYGON_TYPE) 01761 { 01762 fake.poly = 01763 (PolygonType *) Crosshair.AttachedObject.Ptr2; 01764 polyIndex = 01765 GetLowestDistancePolygonPoint (fake.poly, Note.X, 01766 Note.Y); 01767 fake.line.Point1 = fake.poly->Points[polyIndex]; 01768 fake.line.Point2 = fake.poly->Points[ 01769 prev_contour_point (fake.poly, polyIndex)]; 01770 Crosshair.AttachedObject.Ptr2 = &fake.line; 01771 01772 } 01773 Crosshair.AttachedObject.State = STATE_SECOND; 01774 InsertedPoint = *AdjustInsertPoint (); 01775 } 01776 } 01777 break; 01778 01779 /* second notify, insert new point into object */ 01780 case STATE_SECOND: 01781 if (Crosshair.AttachedObject.Type == POLYGON_TYPE) 01782 InsertPointIntoObject (POLYGON_TYPE, 01783 Crosshair.AttachedObject.Ptr1, fake.poly, 01784 &polyIndex, 01785 InsertedPoint.X, InsertedPoint.Y, false, false); 01786 else 01787 InsertPointIntoObject (Crosshair.AttachedObject.Type, 01788 Crosshair.AttachedObject.Ptr1, 01789 Crosshair.AttachedObject.Ptr2, 01790 &polyIndex, 01791 InsertedPoint.X, InsertedPoint.Y, false, false); 01792 SetChangedFlag (true); 01793 01794 /* reset identifiers */ 01795 Crosshair.AttachedObject.Type = NO_TYPE; 01796 Crosshair.AttachedObject.State = STATE_FIRST; 01797 break; 01798 } 01799 break; 01800 } 01801 } 01802 01803 01804 /* --------------------------------------------------------------------------- */ 01805 01806 static const char atomic_syntax[] = N_("Atomic(Save|Restore|Close|Block)"); 01807 01808 static const char atomic_help[] = N_("Save or restore the undo serial number."); 01809 01810 /* %start-doc actions Atomic 01811 01812 This action allows making multiple-action bindings into an atomic 01813 operation that will be undone by a single Undo command. For example, 01814 to optimize rat lines, you'd delete the rats and re-add them. To 01815 group these into a single undo, you'd want the deletions and the 01816 additions to have the same undo serial number. So, you @code{Save}, 01817 delete the rats, @code{Restore}, add the rats - using the same serial 01818 number as the deletes, then @code{Block}, which checks to see if the 01819 deletions or additions actually did anything. If not, the serial 01820 number is set to the saved number, as there's nothing to undo. If 01821 something did happen, the serial number is incremented so that these 01822 actions are counted as a single undo step. 01823 01824 @table @code 01825 01826 @item Save 01827 Saves the undo serial number. 01828 01829 @item Restore 01830 Returns it to the last saved number. 01831 01832 @item Close 01833 Sets it to 1 greater than the last save. 01834 01835 @item Block 01836 Does a Restore if there was nothing to undo, else does a Close. 01837 01838 @end table 01839 01840 %end-doc */ 01841 01842 static int 01843 ActionAtomic (int argc, char **argv, Coord x, Coord y) 01844 { 01845 if (argc != 1) 01846 AFAIL (atomic); 01847 01848 switch (GetFunctionID (argv[0])) 01849 { 01850 case F_Save: 01851 SaveUndoSerialNumber (); 01852 break; 01853 case F_Restore: 01854 RestoreUndoSerialNumber (); 01855 break; 01856 case F_Close: 01857 RestoreUndoSerialNumber (); 01858 IncrementUndoSerialNumber (); 01859 break; 01860 case F_Block: 01861 RestoreUndoSerialNumber (); 01862 if (Bumped) 01863 IncrementUndoSerialNumber (); 01864 break; 01865 } 01866 return 0; 01867 } 01868 01869 /* -------------------------------------------------------------------------- */ 01870 01871 static const char drc_syntax[] = N_("DRC()"); 01872 01873 static const char drc_help[] = N_("Invoke the DRC check."); 01874 01875 /* %start-doc actions DRC 01876 01877 Note that the design rule check uses the current board rule settings, 01878 not the current style settings. 01879 01880 %end-doc */ 01881 01882 static int 01883 ActionDRCheck (int argc, char **argv, Coord x, Coord y) 01884 { 01885 int count; 01886 01887 if (gui->drc_gui == NULL || gui->drc_gui->log_drc_overview) 01888 { 01889 Message (_("%m+Rules are minspace %$mS, minoverlap %$mS " 01890 "minwidth %$mS, minsilk %$mS\n" 01891 "min drill %$mS, min annular ring %$mS\n"), 01892 Settings.grid_unit->allow, 01893 PCB->Bloat, PCB->Shrink, 01894 PCB->minWid, PCB->minSlk, 01895 PCB->minDrill, PCB->minRing); 01896 } 01897 count = DRCAll (); 01898 if (gui->drc_gui == NULL || gui->drc_gui->log_drc_overview) 01899 { 01900 if (count == 0) 01901 Message (_("No DRC problems found.\n")); 01902 else if (count > 0) 01903 Message (_("Found %d design rule errors.\n"), count); 01904 else 01905 Message (_("Aborted DRC after %d design rule errors.\n"), -count); 01906 } 01907 return 0; 01908 } 01909 01910 /* -------------------------------------------------------------------------- */ 01911 01912 static const char dumplibrary_syntax[] = N_("DumpLibrary()"); 01913 01914 static const char dumplibrary_help[] = 01915 N_("Display the entire contents of the libraries."); 01916 01917 /* %start-doc actions DumpLibrary 01918 01919 01920 %end-doc */ 01921 01922 static int 01923 ActionDumpLibrary (int argc, char **argv, Coord x, Coord y) 01924 { 01925 int i, j; 01926 01927 printf ("**** Do not count on this format. It will change ****\n\n"); 01928 printf ("MenuN = %d\n", (int) Library.MenuN); 01929 printf ("MenuMax = %d\n", (int) Library.MenuMax); 01930 for (i = 0; i < Library.MenuN; i++) 01931 { 01932 printf ("Library #%d:\n", i); 01933 printf (" EntryN = %d\n", (int) Library.Menu[i].EntryN); 01934 printf (" EntryMax = %d\n", (int) Library.Menu[i].EntryMax); 01935 printf (" Name = \"%s\"\n", UNKNOWN (Library.Menu[i].Name)); 01936 printf (" directory = \"%s\"\n", 01937 UNKNOWN (Library.Menu[i].directory)); 01938 printf (" Style = \"%s\"\n", UNKNOWN (Library.Menu[i].Style)); 01939 printf (" flag = %d\n", Library.Menu[i].flag); 01940 01941 for (j = 0; j < Library.Menu[i].EntryN; j++) 01942 { 01943 printf (" #%4d: ", j); 01944 if (Library.Menu[i].Entry[j].Template == (char *) -1) 01945 { 01946 printf ("newlib: \"%s\"\n", 01947 UNKNOWN (Library.Menu[i].Entry[j].ListEntry)); 01948 } 01949 else 01950 { 01951 printf ("\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"\n", 01952 UNKNOWN (Library.Menu[i].Entry[j].ListEntry), 01953 UNKNOWN (Library.Menu[i].Entry[j].Template), 01954 UNKNOWN (Library.Menu[i].Entry[j].Package), 01955 UNKNOWN (Library.Menu[i].Entry[j].Value), 01956 UNKNOWN (Library.Menu[i].Entry[j].Description)); 01957 } 01958 } 01959 } 01960 01961 return 0; 01962 } 01963 01964 /* -------------------------------------------------------------------------- */ 01965 01966 static const char flip_syntax[] = N_("Flip(Object|Selected|SelectedElements)"); 01967 01968 static const char flip_help[] = 01969 N_("Flip an element to the opposite side of the board."); 01970 01971 /* %start-doc actions Flip 01972 01973 Note that the location of the element will be symmetric about the 01974 cursor location; i.e. if the part you are pointing at will still be at 01975 the same spot once the element is on the other side. When flipping 01976 multiple elements, this retains their positions relative to each 01977 other, not their absolute positions on the board. 01978 01979 %end-doc */ 01980 01981 static int 01982 ActionFlip (int argc, char **argv, Coord x, Coord y) 01983 { 01984 char *function = ARG (0); 01985 ElementType *element; 01986 void *ptrtmp; 01987 int err = 0; 01988 01989 if (function) 01990 { 01991 switch (GetFunctionID (function)) 01992 { 01993 case F_Object: 01994 if ((SearchScreen (x, y, ELEMENT_TYPE, 01995 &ptrtmp, &ptrtmp, &ptrtmp)) != NO_TYPE) 01996 { 01997 element = (ElementType *) ptrtmp; 01998 ChangeElementSide (element, 2 * Crosshair.Y - PCB->MaxHeight); 01999 IncrementUndoSerialNumber (); 02000 Draw (); 02001 } 02002 break; 02003 case F_Selected: 02004 case F_SelectedElements: 02005 ChangeSelectedElementSide (); 02006 break; 02007 default: 02008 err = 1; 02009 break; 02010 } 02011 if (!err) 02012 return 0; 02013 } 02014 02015 AFAIL (flip); 02016 } 02017 02018 /* -------------------------------------------------------------------------- */ 02019 02020 static const char message_syntax[] = N_("Message(message)"); 02021 02022 static const char message_help[] = N_("Writes a message to the log window."); 02023 02024 /* %start-doc actions Message 02025 02026 This action displays a message to the log window. This action is primarily 02027 provided for use by other programs which may interface with PCB. If 02028 multiple arguments are given, each one is sent to the log window 02029 followed by a newline. 02030 02031 %end-doc */ 02032 02033 static int 02034 ActionMessage (int argc, char **argv, Coord x, Coord y) 02035 { 02036 int i; 02037 02038 if (argc < 1) 02039 AFAIL (message); 02040 02041 for (i = 0; i < argc; i++) 02042 { 02043 Message (argv[i]); 02044 Message ("\n"); 02045 } 02046 02047 return 0; 02048 } 02049 02050 02051 /* -------------------------------------------------------------------------- */ 02052 02053 static const char setthermal_syntax[] = 02054 "SetThermal(Object|SelectedPins|SelectedVias|Selected, Style)"; 02055 02056 static const char setthermal_help[] = 02057 N_("Set the thermal (on the current layer) of pins or vias to the given style.\n" 02058 "Style = 0 means no thermal.\n" 02059 "Style = 1 has diagonal fingers with sharp edges.\n" 02060 "Style = 2 has horizontal and vertical fingers with sharp edges.\n" 02061 "Style = 3 is a solid connection to the plane.\n" 02062 "Style = 4 has diagonal fingers with rounded edges.\n" 02063 "Style = 5 has horizontal and vertical fingers with rounded edges.\n"); 02064 02065 /* %start-doc actions SetThermal 02066 02067 This changes how/whether pins or vias connect to any rectangle or polygon 02068 on the current layer. The first argument can specify one object, or all 02069 selected pins, or all selected vias, or all selected pins and vias. 02070 The second argument specifies the style of connection. 02071 There are 5 possibilities: 02072 0 - no connection, 02073 1 - 45 degree fingers with sharp edges, 02074 2 - horizontal & vertical fingers with sharp edges, 02075 3 - solid connection, 02076 4 - 45 degree fingers with rounded corners, 02077 5 - horizontal & vertical fingers with rounded corners. 02078 02079 Pins and Vias may have thermals whether or not there is a polygon available 02080 to connect with. However, they will have no effect without the polygon. 02081 %end-doc */ 02082 02083 static int 02084 ActionSetThermal (int argc, char **argv, Coord x, Coord y) 02085 { 02086 char *function = ARG (0); 02087 char *style = ARG (1); 02088 void *ptr1, *ptr2, *ptr3; 02089 int type, kind; 02090 int err = 0; 02091 02092 if (function && *function) 02093 { 02094 bool absolute; 02095 02096 if ( ! style || ! *style) 02097 { 02098 kind = PCB->ThermStyle; 02099 absolute = true; 02100 } 02101 else 02102 kind = GetUnitlessValue (style, &absolute); 02103 02104 /* To allow relative values we could search for the first selected 02105 item and make 'kind' relative to that, but that's not too useful 02106 and requires quite some code. For example there's no 02107 GetFirstSelectedPin() function available. Let's postpone this 02108 functionality, there are more urgent things to do. */ 02109 02110 if (absolute) 02111 switch (GetFunctionID (function)) 02112 { 02113 case F_Object: 02114 if ((type = 02115 SearchScreen (Crosshair.X, Crosshair.Y, CHANGETHERMAL_TYPES, 02116 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 02117 { 02118 ChangeObjectThermal (type, ptr1, ptr2, ptr3, kind); 02119 IncrementUndoSerialNumber (); 02120 Draw (); 02121 } 02122 break; 02123 case F_SelectedPins: 02124 ChangeSelectedThermals (PIN_TYPE, kind); 02125 break; 02126 case F_SelectedVias: 02127 ChangeSelectedThermals (VIA_TYPE, kind); 02128 break; 02129 case F_Selected: 02130 case F_SelectedElements: 02131 ChangeSelectedThermals (CHANGETHERMAL_TYPES, kind); 02132 break; 02133 default: 02134 err = 1; 02135 break; 02136 } 02137 else 02138 err = 1; 02139 } 02140 else 02141 err = 1; 02142 02143 if (err) 02144 AFAIL (setthermal); 02145 02146 return 0; 02147 } 02148 02155 void 02156 EventMoveCrosshair (int ev_x, int ev_y) 02157 { 02158 #ifdef HAVE_LIBSTROKE 02159 if (mid_stroke) 02160 { 02161 StrokeBox.X2 = ev_x; 02162 StrokeBox.Y2 = ev_y; 02163 stroke_record (ev_x, ev_y); 02164 return; 02165 } 02166 #endif /* HAVE_LIBSTROKE */ 02167 if (MoveCrosshairAbsolute (ev_x, ev_y)) 02168 { 02169 /* update object position and cursor location */ 02170 AdjustAttachedObjects (); 02171 notify_crosshair_change (true); 02172 } 02173 } 02174 02175 /* --------------------------------------------------------------------------- */ 02176 02177 static const char setvalue_syntax[] = 02178 N_("SetValue(Grid|Line|LineSize|Text|TextScale|ViaDrillingHole|Via|ViaSize, " 02179 "delta)"); 02180 02181 static const char setvalue_help[] = 02182 N_("Change various board-wide values and sizes."); 02183 02184 /* %start-doc actions SetValue 02185 02186 @table @code 02187 02188 @item ViaDrillingHole 02189 Changes the diameter of the drill for new vias. 02190 02191 @item Grid 02192 Sets the grid spacing. 02193 02194 @item Line 02195 @item LineSize 02196 Changes the thickness of new lines. 02197 02198 @item Via 02199 @item ViaSize 02200 Changes the diameter of new vias. 02201 02202 @item Text 02203 @item TextScale 02204 Changes the size of new text. 02205 02206 @end table 02207 02208 %end-doc */ 02209 02210 static int 02211 ActionSetValue (int argc, char **argv, Coord x, Coord y) 02212 { 02213 char *function = ARG (0); 02214 char *val = ARG (1); 02215 char *units = ARG (2); 02216 bool absolute; /* flag for 'absolute' value */ 02217 double value; 02218 int text_scale; 02219 int err = 0; 02220 02221 if (function && val) 02222 { 02223 value = GetValue (val, units, &absolute); 02224 switch (GetFunctionID (function)) 02225 { 02226 case F_ViaDrillingHole: 02227 SetViaDrillingHole (absolute ? value : 02228 value + Settings.ViaDrillingHole, 02229 false); 02230 hid_action ("RouteStylesChanged"); 02231 break; 02232 02233 case F_Grid: 02234 if (absolute) 02235 SetGrid (value, false); 02236 else 02237 { 02238 if (value == 0) 02239 value = val[0] == '-' ? -Settings.increments->grid 02240 : Settings.increments->grid; 02241 /* On the way down, short against the minimum 02242 * PCB drawing unit */ 02243 if ((value + PCB->Grid) < 1) 02244 SetGrid (1, false); 02245 else if (PCB->Grid == 1) 02246 SetGrid (value, false); 02247 else 02248 SetGrid (value + PCB->Grid, false); 02249 } 02250 break; 02251 02252 case F_LineSize: 02253 case F_Line: 02254 if (!absolute && value == 0) 02255 value = val[0] == '-' ? -Settings.increments->line 02256 : Settings.increments->line; 02257 SetLineSize (absolute ? value : value + Settings.LineThickness); 02258 hid_action ("RouteStylesChanged"); 02259 break; 02260 02261 case F_Via: 02262 case F_ViaSize: 02263 SetViaSize (absolute ? value : value + Settings.ViaThickness, false); 02264 hid_action ("RouteStylesChanged"); 02265 break; 02266 02267 case F_Text: 02268 case F_TextScale: 02269 text_scale = value / (double)FONT_CAPHEIGHT * 100.; 02270 if (!absolute) 02271 text_scale += Settings.TextScale; 02272 SetTextScale (text_scale); 02273 break; 02274 default: 02275 err = 1; 02276 break; 02277 } 02278 if (!err) 02279 return 0; 02280 } 02281 02282 AFAIL (setvalue); 02283 } 02284 02285 02286 /* --------------------------------------------------------------------------- */ 02287 02288 static const char quit_syntax[] = N_("Quit()"); 02289 02290 static const char quit_help[] = N_("Quits the application after confirming."); 02291 02292 /* %start-doc actions Quit 02293 02294 If you have unsaved changes, you will be prompted to confirm (or 02295 save) before quitting. 02296 02297 %end-doc */ 02298 02299 static int 02300 ActionQuit (int argc, char **argv, Coord x, Coord y) 02301 { 02302 char *force = ARG (0); 02303 if (force && strcasecmp (force, "force") == 0) 02304 { 02305 PCB->Changed = 0; 02306 exit (0); 02307 } 02308 if (!PCB->Changed || gui->close_confirm_dialog () == HID_CLOSE_CONFIRM_OK) 02309 QuitApplication (); 02310 return 1; 02311 } 02312 02313 /* --------------------------------------------------------------------------- */ 02314 02315 static const char connection_syntax[] = 02316 N_("Connection(Find|ResetLinesAndPolygons|ResetPinsAndVias|Reset)"); 02317 02318 static const char connection_help[] = 02319 N_("Searches connections of the object at the cursor position."); 02320 02321 /* %start-doc actions Connection 02322 02323 Connections found with this action will be highlighted in the 02324 ``connected-color'' color and will have the ``found'' flag set. 02325 02326 @table @code 02327 02328 @item Find 02329 The net under the cursor is ``found''. 02330 02331 @item ResetLinesAndPolygons 02332 Any ``found'' lines and polygons are marked ``not found''. 02333 02334 @item ResetPinsAndVias 02335 Any ``found'' pins and vias are marked ``not found''. 02336 02337 @item Reset 02338 All ``found'' objects are marked ``not found''. 02339 02340 @end table 02341 02342 %end-doc */ 02343 02344 static int 02345 ActionConnection (int argc, char **argv, Coord x, Coord y) 02346 { 02347 char *function = ARG (0); 02348 if (function) 02349 { 02350 switch (GetFunctionID (function)) 02351 { 02352 case F_Find: 02353 { 02354 gui->get_coords (_("Click on a connection"), &x, &y); 02355 LookupConnection (x, y, true, 1, CONNECTEDFLAG, false); 02356 LookupConnection (x, y, true, 1, FOUNDFLAG, true); 02357 break; 02358 } 02359 02360 case F_ResetLinesAndPolygons: 02361 if (ClearFlagOnLinesAndPolygons (true, CONNECTEDFLAG | FOUNDFLAG)) 02362 { 02363 IncrementUndoSerialNumber (); 02364 Draw (); 02365 } 02366 break; 02367 02368 case F_ResetPinsViasAndPads: 02369 if (ClearFlagOnPinsViasAndPads (true, CONNECTEDFLAG | FOUNDFLAG)) 02370 { 02371 IncrementUndoSerialNumber (); 02372 Draw (); 02373 } 02374 break; 02375 02376 case F_Reset: 02377 if (ClearFlagOnAllObjects (true, CONNECTEDFLAG | FOUNDFLAG)) 02378 { 02379 IncrementUndoSerialNumber (); 02380 Draw (); 02381 } 02382 break; 02383 } 02384 return 0; 02385 } 02386 02387 AFAIL (connection); 02388 } 02389 02390 /* --------------------------------------------------------------------------- */ 02391 02392 static const char disperseelements_syntax[] = 02393 N_("DisperseElements(All|Selected)"); 02394 02395 static const char disperseelements_help[] = N_("Disperses elements."); 02396 02397 /* %start-doc actions DisperseElements 02398 02399 Normally this is used when starting a board, by selecting all elements 02400 and then dispersing them. This scatters the elements around the board 02401 so that you can pick individual ones, rather than have all the 02402 elements at the same 0,0 coordinate and thus impossible to choose 02403 from. 02404 02405 %end-doc */ 02406 02407 #define GAP MIL_TO_COORD(100) 02408 02409 static int 02410 ActionDisperseElements (int argc, char **argv, Coord x, Coord y) 02411 { 02412 char *function = ARG (0); 02413 Coord minx = GAP, 02414 miny = GAP, 02415 maxy = GAP, 02416 dx, dy; 02417 int all = 0, bad = 0; 02418 02419 if (!function || !*function) 02420 { 02421 bad = 1; 02422 } 02423 else 02424 { 02425 switch (GetFunctionID (function)) 02426 { 02427 case F_All: 02428 all = 1; 02429 break; 02430 02431 case F_Selected: 02432 all = 0; 02433 break; 02434 02435 default: 02436 bad = 1; 02437 } 02438 } 02439 02440 if (bad) 02441 { 02442 AFAIL (disperseelements); 02443 } 02444 02445 02446 ELEMENT_LOOP (PCB->Data); 02447 { 02448 /* 02449 * If we want to disperse selected elements, maybe we need smarter 02450 * code here to avoid putting components on top of others which 02451 * are not selected. For now, I'm assuming that this is typically 02452 * going to be used either with a brand new design or a scratch 02453 * design holding some new components 02454 */ 02455 if (!TEST_FLAG (LOCKFLAG, element) && (all || TEST_FLAG (SELECTEDFLAG, element))) 02456 { 02457 02458 /* figure out how much to move the element */ 02459 dx = minx - element->BoundingBox.X1; 02460 02461 /* snap to the grid */ 02462 dx -= (element->MarkX + dx) % PCB->Grid; 02463 02464 /* 02465 * and add one grid size so we make sure we always space by GAP or 02466 * more 02467 */ 02468 dx += PCB->Grid; 02469 02470 /* Figure out if this row has room. If not, start a new row */ 02471 if (GAP + element->BoundingBox.X2 + dx > PCB->MaxWidth) 02472 { 02473 miny = maxy + GAP; 02474 minx = GAP; 02475 } 02476 02477 /* figure out how much to move the element */ 02478 dx = minx - element->BoundingBox.X1; 02479 dy = miny - element->BoundingBox.Y1; 02480 02481 /* snap to the grid */ 02482 dx -= (element->MarkX + dx) % PCB->Grid; 02483 dx += PCB->Grid; 02484 dy -= (element->MarkY + dy) % PCB->Grid; 02485 dy += PCB->Grid; 02486 02487 /* move the element */ 02488 MoveElementLowLevel (PCB->Data, element, dx, dy); 02489 02490 /* and add to the undo list so we can undo this operation */ 02491 AddObjectToMoveUndoList (ELEMENT_TYPE, NULL, NULL, element, dx, dy); 02492 02493 /* keep track of how tall this row is */ 02494 minx += element->BoundingBox.X2 - element->BoundingBox.X1 + GAP; 02495 if (maxy < element->BoundingBox.Y2) 02496 { 02497 maxy = element->BoundingBox.Y2; 02498 } 02499 } 02500 02501 } 02502 END_LOOP; 02503 02504 /* done with our action so increment the undo # */ 02505 IncrementUndoSerialNumber (); 02506 02507 Redraw (); 02508 SetChangedFlag (true); 02509 02510 return 0; 02511 } 02512 02513 #undef GAP 02514 02515 /* --------------------------------------------------------------------------- */ 02516 02517 static const char display_syntax[] = 02518 N_("Display(NameOnPCB|Description|Value)\n" 02519 "Display(Grid|Redraw)\n" 02520 "Display(CycleClip|CycleCrosshair|Toggle45Degree|ToggleStartDirection)\n" 02521 "Display(ToggleGrid|ToggleRubberBandMode|ToggleUniqueNames)\n" 02522 "Display(ToggleMask|ToggleName|ToggleClearLine|ToggleFullPoly|ToggleSnapPin)\n" 02523 "Display(ToggleThindraw|ToggleThindrawPoly|ToggleOrthoMove|ToggleLocalRef)\n" 02524 "Display(ToggleCheckPlanes|ToggleShowDRC|ToggleAutoDRC)\n" 02525 "Display(ToggleLiveRoute|LockNames|OnlyNames)\n" 02526 "Display(Pinout|PinOrPadName)"); 02527 02528 static const char display_help[] = N_("Several display-related actions."); 02529 02530 /* %start-doc actions Display 02531 02532 @table @code 02533 02534 @item NameOnPCB 02535 @item Description 02536 @item Value 02537 Specify whether all elements show their name, description, or value. 02538 02539 @item Redraw 02540 Redraw the whole board. 02541 02542 @item Toggle45Degree 02543 When clear, lines can be drawn at any angle. When set, lines are 02544 restricted to multiples of 45 degrees and requested lines may be 02545 broken up according to the clip setting. 02546 02547 @item CycleClip 02548 Changes the way lines are restricted to 45 degree increments. The 02549 various settings are: straight only, orthogonal then angled, and angled 02550 then orthogonal. If AllDirections is set, this action disables it. 02551 02552 @item CycleCrosshair 02553 Changes crosshair drawing. Crosshair may accept form of 4-ray, 02554 8-ray and 12-ray cross. 02555 02556 @item ToggleRubberBandMode 02557 If set, moving an object moves all the lines attached to it too. 02558 02559 @item ToggleStartDirection 02560 If set, each time you set a point in a line, the Clip toggles between 02561 orth-angle and angle-ortho. 02562 02563 @item ToggleUniqueNames 02564 If set, you will not be permitted to change the name of an element to 02565 match that of another element. 02566 02567 @item ToggleSnapPin 02568 If set, pin centers and pad end points are treated as additional grid 02569 points that the cursor can snap to. 02570 02571 @item ToggleLocalRef 02572 If set, the mark is automatically set to the beginning of any move, so 02573 you can see the relative distance you've moved. 02574 02575 @item ToggleThindraw 02576 If set, objects on the screen are drawn as outlines (lines are drawn 02577 as center-lines). This lets you see line endpoints hidden under pins, 02578 for example. 02579 02580 @item ToggleThindrawPoly 02581 If set, polygons on the screen are drawn as outlines. 02582 02583 @item ToggleShowDRC 02584 If set, pending objects (i.e. lines you're in the process of drawing) 02585 will be drawn with an outline showing how far away from other copper 02586 you need to be. 02587 02588 @item ToggleLiveRoute 02589 If set, the progress of the autorouter will be visible on the screen. 02590 02591 @item ToggleAutoDRC 02592 If set, you will not be permitted to make connections which violate 02593 the current DRC and netlist settings. 02594 02595 @item ToggleCheckPlanes 02596 If set, lines and arcs aren't drawn, which usually leaves just the 02597 polygons. If you also disable all but the layer you're interested in, 02598 this allows you to check for isolated regions. 02599 02600 @item ToggleOrthoMove 02601 If set, the crosshair is only allowed to move orthogonally from its 02602 previous position. I.e. you can move an element or line up, down, 02603 left, or right, but not up+left or down+right. 02604 02605 @item ToggleName 02606 Selects whether the pinouts show the pin names or the pin numbers. 02607 02608 @item ToggleLockNames 02609 If set, text will ignore left mouse clicks and actions that work on 02610 objects under the mouse. You can still select text with a lasso (left 02611 mouse drag) and perform actions on the selection. 02612 02613 @item ToggleOnlyNames 02614 If set, only text will be sensitive for mouse clicks and actions that 02615 work on objects under the mouse. You can still select other objects 02616 with a lasso (left mouse drag) and perform actions on the selection. 02617 02618 @item ToggleMask 02619 Turns the solder mask on or off. 02620 02621 @item ToggleClearLine 02622 When set, the clear-line flag causes new lines and arcs to have their 02623 ``clear polygons'' flag set, so they won't be electrically connected 02624 to any polygons they overlap. 02625 02626 @item ToggleFullPoly 02627 When set, the full-poly flag causes new polygons to have their 02628 ``full polygon'' flag set, so all parts of them will be displayed 02629 instead of only the biggest one. 02630 02631 @item ToggleGrid 02632 Resets the origin of the current grid to be wherever the mouse pointer 02633 is (not where the crosshair currently is). If you provide two numbers 02634 after this, the origin is set to that coordinate. 02635 02636 @item Grid 02637 Toggles whether the grid is displayed or not. 02638 02639 @item Pinout 02640 Causes the pinout of the element indicated by the cursor to be 02641 displayed, usually in a separate window. 02642 02643 @item PinOrPadName 02644 Toggles whether the names of pins, pads, or (yes) vias will be 02645 displayed. If the cursor is over an element, all of its pins and pads 02646 are affected. 02647 02648 @item ToggleAutoBuriedVias 02649 If set, automatically created vias are buried vias. 02650 02651 @end table 02652 02653 %end-doc */ 02654 02655 static enum crosshair_shape 02656 CrosshairShapeIncrement (enum crosshair_shape shape) 02657 { 02658 switch(shape) 02659 { 02660 case Basic_Crosshair_Shape: 02661 shape = Union_Jack_Crosshair_Shape; 02662 break; 02663 case Union_Jack_Crosshair_Shape: 02664 shape = Dozen_Crosshair_Shape; 02665 break; 02666 case Dozen_Crosshair_Shape: 02667 shape = Crosshair_Shapes_Number; 02668 break; 02669 case Crosshair_Shapes_Number: 02670 shape = Basic_Crosshair_Shape; 02671 break; 02672 } 02673 return shape; 02674 } 02675 02676 static int 02677 ActionDisplay (int argc, char **argv, Coord childX, Coord childY) 02678 { 02679 char *function, *str_dir; 02680 int id; 02681 int err = 0; 02682 02683 function = ARG (0); 02684 str_dir = ARG (1); 02685 02686 if (function && (!str_dir || !*str_dir)) 02687 { 02688 switch (id = GetFunctionID (function)) 02689 { 02690 02691 /* redraw layout */ 02692 case F_ClearAndRedraw: 02693 case F_Redraw: 02694 Redraw (); 02695 break; 02696 02697 /* change the displayed name of elements */ 02698 case F_Value: 02699 case F_NameOnPCB: 02700 case F_Description: 02701 ELEMENT_LOOP (PCB->Data); 02702 { 02703 EraseElementName (element); 02704 } 02705 END_LOOP; 02706 CLEAR_FLAG (DESCRIPTIONFLAG | NAMEONPCBFLAG, PCB); 02707 switch (id) 02708 { 02709 case F_Value: 02710 break; 02711 case F_NameOnPCB: 02712 SET_FLAG (NAMEONPCBFLAG, PCB); 02713 break; 02714 case F_Description: 02715 SET_FLAG (DESCRIPTIONFLAG, PCB); 02716 break; 02717 } 02718 ELEMENT_LOOP (PCB->Data); 02719 { 02720 DrawElementName (element); 02721 } 02722 END_LOOP; 02723 Draw (); 02724 break; 02725 02726 /* toggle line-adjust flag */ 02727 case F_ToggleAllDirections: 02728 TOGGLE_FLAG (ALLDIRECTIONFLAG, PCB); 02729 AdjustAttachedObjects (); 02730 break; 02731 02732 case F_CycleClip: 02733 notify_crosshair_change (false); 02734 if (TEST_FLAG (ALLDIRECTIONFLAG, PCB)) 02735 { 02736 TOGGLE_FLAG (ALLDIRECTIONFLAG, PCB); 02737 PCB->Clipping = 0; 02738 } 02739 else 02740 PCB->Clipping = (PCB->Clipping + 1) % 3; 02741 AdjustAttachedObjects (); 02742 notify_crosshair_change (true); 02743 break; 02744 02745 case F_CycleCrosshair: 02746 notify_crosshair_change (false); 02747 Crosshair.shape = CrosshairShapeIncrement(Crosshair.shape); 02748 if (Crosshair_Shapes_Number == Crosshair.shape) 02749 Crosshair.shape = Basic_Crosshair_Shape; 02750 notify_crosshair_change (true); 02751 break; 02752 02753 case F_ToggleRubberBandMode: 02754 notify_crosshair_change (false); 02755 TOGGLE_FLAG (RUBBERBANDFLAG, PCB); 02756 notify_crosshair_change (true); 02757 break; 02758 02759 case F_ToggleAutoBuriedVias: 02760 notify_crosshair_change (false); 02761 TOGGLE_FLAG (AUTOBURIEDVIASFLAG, PCB); 02762 notify_crosshair_change (true); 02763 break; 02764 02765 case F_ToggleStartDirection: 02766 notify_crosshair_change (false); 02767 TOGGLE_FLAG (SWAPSTARTDIRFLAG, PCB); 02768 notify_crosshair_change (true); 02769 break; 02770 02771 case F_ToggleUniqueNames: 02772 TOGGLE_FLAG (UNIQUENAMEFLAG, PCB); 02773 break; 02774 02775 case F_ToggleSnapPin: 02776 notify_crosshair_change (false); 02777 TOGGLE_FLAG (SNAPPINFLAG, PCB); 02778 notify_crosshair_change (true); 02779 break; 02780 02781 case F_ToggleLocalRef: 02782 TOGGLE_FLAG (LOCALREFFLAG, PCB); 02783 break; 02784 02785 case F_ToggleThindraw: 02786 TOGGLE_FLAG (THINDRAWFLAG, PCB); 02787 Redraw (); 02788 break; 02789 02790 case F_ToggleThindrawPoly: 02791 TOGGLE_FLAG (THINDRAWPOLYFLAG, PCB); 02792 Redraw (); 02793 break; 02794 02795 case F_ToggleLockNames: 02796 TOGGLE_FLAG (LOCKNAMESFLAG, PCB); 02797 CLEAR_FLAG (ONLYNAMESFLAG, PCB); 02798 break; 02799 02800 case F_ToggleOnlyNames: 02801 TOGGLE_FLAG (ONLYNAMESFLAG, PCB); 02802 CLEAR_FLAG (LOCKNAMESFLAG, PCB); 02803 break; 02804 02805 case F_ToggleHideNames: 02806 TOGGLE_FLAG (HIDENAMESFLAG, PCB); 02807 Redraw (); 02808 break; 02809 02810 case F_ToggleShowDRC: 02811 TOGGLE_FLAG (SHOWDRCFLAG, PCB); 02812 break; 02813 02814 case F_ToggleLiveRoute: 02815 TOGGLE_FLAG (LIVEROUTEFLAG, PCB); 02816 break; 02817 02818 case F_ToggleAutoDRC: 02819 notify_crosshair_change (false); 02820 TOGGLE_FLAG (AUTODRCFLAG, PCB); 02821 if (TEST_FLAG (AUTODRCFLAG, PCB) && Settings.Mode == LINE_MODE) 02822 { 02823 if (ClearFlagOnAllObjects (true, CONNECTEDFLAG | FOUNDFLAG)) 02824 { 02825 IncrementUndoSerialNumber (); 02826 Draw (); 02827 } 02828 if (Crosshair.AttachedLine.State != STATE_FIRST) 02829 { 02830 LookupConnection (Crosshair.AttachedLine.Point1.X, 02831 Crosshair.AttachedLine.Point1.Y, 02832 true, 1, CONNECTEDFLAG, false); 02833 LookupConnection (Crosshair.AttachedLine.Point1.X, 02834 Crosshair.AttachedLine.Point1.Y, 02835 true, 1, FOUNDFLAG, true); 02836 } 02837 } 02838 notify_crosshair_change (true); 02839 break; 02840 02841 case F_ToggleCheckPlanes: 02842 TOGGLE_FLAG (CHECKPLANESFLAG, PCB); 02843 Redraw (); 02844 break; 02845 02846 case F_ToggleOrthoMove: 02847 TOGGLE_FLAG (ORTHOMOVEFLAG, PCB); 02848 break; 02849 02850 case F_ToggleName: 02851 TOGGLE_FLAG (SHOWNUMBERFLAG, PCB); 02852 Redraw (); 02853 break; 02854 02855 case F_ToggleMask: 02856 TOGGLE_FLAG (SHOWMASKFLAG, PCB); 02857 Redraw (); 02858 break; 02859 02860 case F_ToggleClearLine: 02861 TOGGLE_FLAG (CLEARNEWFLAG, PCB); 02862 break; 02863 02864 case F_ToggleFullPoly: 02865 TOGGLE_FLAG (NEWFULLPOLYFLAG, PCB); 02866 break; 02867 02868 /* shift grid alignment */ 02869 case F_ToggleGrid: 02870 { 02871 Coord oldGrid = PCB->Grid; 02872 02873 PCB->Grid = 1; 02874 if (MoveCrosshairAbsolute (Crosshair.X, Crosshair.Y)) 02875 notify_crosshair_change (true); /* first notify was in MoveCrosshairAbs */ 02876 SetGrid (oldGrid, true); 02877 } 02878 break; 02879 02880 /* toggle displaying of the grid */ 02881 case F_Grid: 02882 Settings.DrawGrid = !Settings.DrawGrid; 02883 Redraw (); 02884 break; 02885 02886 /* display the pinout of an element */ 02887 case F_Pinout: 02888 { 02889 ElementType *element; 02890 void *ptrtmp; 02891 Coord x, y; 02892 02893 gui->get_coords (_("Click on an element"), &x, &y); 02894 if ((SearchScreen 02895 (x, y, ELEMENT_TYPE, &ptrtmp, 02896 &ptrtmp, &ptrtmp)) != NO_TYPE) 02897 { 02898 element = (ElementType *) ptrtmp; 02899 gui->show_item (element); 02900 } 02901 break; 02902 } 02903 02904 /* toggle displaying of pin/pad/via names */ 02905 case F_PinOrPadName: 02906 { 02907 void *ptr1, *ptr2, *ptr3; 02908 Coord x, y; 02909 02910 gui->get_coords(_("Click on an element"), &x, &y); 02911 02912 switch (SearchScreen (x, y, 02913 ELEMENT_TYPE | PIN_TYPE | PAD_TYPE | 02914 VIA_TYPE, (void **) &ptr1, (void **) &ptr2, 02915 (void **) &ptr3)) 02916 { 02917 case ELEMENT_TYPE: 02918 PIN_LOOP ((ElementType *) ptr1); 02919 { 02920 if (TEST_FLAG (DISPLAYNAMEFLAG, pin)) 02921 ErasePinName (pin); 02922 else 02923 DrawPinName (pin); 02924 AddObjectToFlagUndoList (PIN_TYPE, ptr1, pin, pin); 02925 TOGGLE_FLAG (DISPLAYNAMEFLAG, pin); 02926 } 02927 END_LOOP; 02928 PAD_LOOP ((ElementType *) ptr1); 02929 { 02930 if (TEST_FLAG (DISPLAYNAMEFLAG, pad)) 02931 ErasePadName (pad); 02932 else 02933 DrawPadName (pad); 02934 AddObjectToFlagUndoList (PAD_TYPE, ptr1, pad, pad); 02935 TOGGLE_FLAG (DISPLAYNAMEFLAG, pad); 02936 } 02937 END_LOOP; 02938 SetChangedFlag (true); 02939 IncrementUndoSerialNumber (); 02940 Draw (); 02941 break; 02942 02943 case PIN_TYPE: 02944 if (TEST_FLAG (DISPLAYNAMEFLAG, (PinType *) ptr2)) 02945 ErasePinName ((PinType *) ptr2); 02946 else 02947 DrawPinName ((PinType *) ptr2); 02948 AddObjectToFlagUndoList (PIN_TYPE, ptr1, ptr2, ptr3); 02949 TOGGLE_FLAG (DISPLAYNAMEFLAG, (PinType *) ptr2); 02950 SetChangedFlag (true); 02951 IncrementUndoSerialNumber (); 02952 Draw (); 02953 break; 02954 02955 case PAD_TYPE: 02956 if (TEST_FLAG (DISPLAYNAMEFLAG, (PadType *) ptr2)) 02957 ErasePadName ((PadType *) ptr2); 02958 else 02959 DrawPadName ((PadType *) ptr2); 02960 AddObjectToFlagUndoList (PAD_TYPE, ptr1, ptr2, ptr3); 02961 TOGGLE_FLAG (DISPLAYNAMEFLAG, (PadType *) ptr2); 02962 SetChangedFlag (true); 02963 IncrementUndoSerialNumber (); 02964 Draw (); 02965 break; 02966 case VIA_TYPE: 02967 if (TEST_FLAG (DISPLAYNAMEFLAG, (PinType *) ptr2)) 02968 EraseViaName ((PinType *) ptr2); 02969 else 02970 DrawViaName ((PinType *) ptr2); 02971 AddObjectToFlagUndoList (VIA_TYPE, ptr1, ptr2, ptr3); 02972 TOGGLE_FLAG (DISPLAYNAMEFLAG, (PinType *) ptr2); 02973 SetChangedFlag (true); 02974 IncrementUndoSerialNumber (); 02975 Draw (); 02976 break; 02977 } 02978 break; 02979 } 02980 default: 02981 err = 1; 02982 } 02983 } 02984 else if (function && str_dir) 02985 { 02986 switch (GetFunctionID (function)) 02987 { 02988 case F_ToggleGrid: 02989 if (argc > 2) 02990 { 02991 PCB->GridOffsetX = GetValue (argv[1], NULL, NULL); 02992 PCB->GridOffsetY = GetValue (argv[2], NULL, NULL); 02993 if (Settings.DrawGrid) 02994 Redraw (); 02995 } 02996 break; 02997 02998 default: 02999 err = 1; 03000 break; 03001 } 03002 } 03003 else 03004 err = 1; 03005 03006 if (err) 03007 AFAIL (display); 03008 03009 return 0; 03010 } 03011 03012 /* --------------------------------------------------------------------------- */ 03013 03014 static const char mode_syntax[] = 03015 N_("Mode(Arc|Arrow|Copy|InsertPoint|Line|Lock|Move|None|PasteBuffer)\n" 03016 "Mode(Polygon|Rectangle|Remove|Rotate|Text|Thermal|Via)\n" 03017 "Mode(Notify|Release|Cancel|Stroke)\n" 03018 "Mode(Save|Restore)"); 03019 03020 static const char mode_help[] = N_("Change or use the tool mode."); 03021 03022 /* %start-doc actions Mode 03023 03024 @table @code 03025 03026 @item Arc 03027 @itemx Arrow 03028 @itemx Copy 03029 @itemx InsertPoint 03030 @itemx Line 03031 @itemx Lock 03032 @itemx Move 03033 @itemx None 03034 @itemx PasteBuffer 03035 @itemx Polygon 03036 @itemx Rectangle 03037 @itemx Remove 03038 @itemx Rotate 03039 @itemx Text 03040 @itemx Thermal 03041 @itemx Via 03042 Select the indicated tool. 03043 03044 @item Notify 03045 Called when you press the mouse button, or move the mouse. 03046 03047 @item Release 03048 Called when you release the mouse button. 03049 03050 @item Cancel 03051 Cancels any pending tool activity, allowing you to restart elsewhere. 03052 For example, this allows you to start a new line rather than attach a 03053 line to the previous line. 03054 03055 @item Escape 03056 Similar to Cancel but calling this action a second time will return 03057 to the Arrow tool. 03058 03059 @item Stroke 03060 If your @code{pcb} was built with libstroke, this invokes the stroke 03061 input method. If not, this will restart a drawing mode if you were 03062 drawing, else it will select objects. 03063 03064 @item Save 03065 Remembers the current tool. 03066 03067 @item Restore 03068 Restores the tool to the last saved tool. 03069 03070 @end table 03071 03072 %end-doc */ 03073 03074 static int 03075 ActionMode (int argc, char **argv, Coord x, Coord y) 03076 { 03077 char *function = ARG (0); 03078 03079 if (function) 03080 { 03081 Note.X = Crosshair.X; 03082 Note.Y = Crosshair.Y; 03083 notify_crosshair_change (false); 03084 switch (GetFunctionID (function)) 03085 { 03086 case F_Arc: 03087 SetMode (ARC_MODE); 03088 break; 03089 case F_Arrow: 03090 SetMode (ARROW_MODE); 03091 break; 03092 case F_Copy: 03093 SetMode (COPY_MODE); 03094 break; 03095 case F_InsertPoint: 03096 SetMode (INSERTPOINT_MODE); 03097 break; 03098 case F_Line: 03099 SetMode (LINE_MODE); 03100 break; 03101 case F_Lock: 03102 SetMode (LOCK_MODE); 03103 break; 03104 case F_Move: 03105 SetMode (MOVE_MODE); 03106 break; 03107 case F_None: 03108 SetMode (NO_MODE); 03109 break; 03110 case F_Cancel: 03111 { 03112 int saved_mode = Settings.Mode; 03113 SetMode (NO_MODE); 03114 SetMode (saved_mode); 03115 } 03116 break; 03117 case F_Escape: 03118 { 03119 switch (Settings.Mode) 03120 { 03121 case VIA_MODE: 03122 case PASTEBUFFER_MODE: 03123 case TEXT_MODE: 03124 case ROTATE_MODE: 03125 case REMOVE_MODE: 03126 case MOVE_MODE: 03127 case COPY_MODE: 03128 case INSERTPOINT_MODE: 03129 case RUBBERBANDMOVE_MODE: 03130 case THERMAL_MODE: 03131 case LOCK_MODE: 03132 SetMode (NO_MODE); 03133 SetMode (ARROW_MODE); 03134 break; 03135 03136 case LINE_MODE: 03137 if (Crosshair.AttachedLine.State == STATE_FIRST) 03138 SetMode (ARROW_MODE); 03139 else 03140 { 03141 SetMode (NO_MODE); 03142 SetMode (LINE_MODE); 03143 } 03144 break; 03145 03146 case RECTANGLE_MODE: 03147 if (Crosshair.AttachedBox.State == STATE_FIRST) 03148 SetMode (ARROW_MODE); 03149 else 03150 { 03151 SetMode (NO_MODE); 03152 SetMode (RECTANGLE_MODE); 03153 } 03154 break; 03155 03156 case POLYGON_MODE: 03157 if (Crosshair.AttachedLine.State == STATE_FIRST) 03158 SetMode (ARROW_MODE); 03159 else 03160 { 03161 SetMode (NO_MODE); 03162 SetMode (POLYGON_MODE); 03163 } 03164 break; 03165 03166 case POLYGONHOLE_MODE: 03167 if (Crosshair.AttachedLine.State == STATE_FIRST) 03168 SetMode (ARROW_MODE); 03169 else 03170 { 03171 SetMode (NO_MODE); 03172 SetMode (POLYGONHOLE_MODE); 03173 } 03174 break; 03175 03176 case ARC_MODE: 03177 if (Crosshair.AttachedBox.State == STATE_FIRST) 03178 SetMode (ARROW_MODE); 03179 else 03180 { 03181 SetMode (NO_MODE); 03182 SetMode (ARC_MODE); 03183 } 03184 break; 03185 03186 case ARROW_MODE: 03187 break; 03188 03189 default: 03190 break; 03191 } 03192 } 03193 break; 03194 03195 case F_Notify: 03196 NotifyMode (); 03197 break; 03198 case F_PasteBuffer: 03199 SetMode (PASTEBUFFER_MODE); 03200 break; 03201 case F_Polygon: 03202 SetMode (POLYGON_MODE); 03203 break; 03204 case F_PolygonHole: 03205 SetMode (POLYGONHOLE_MODE); 03206 break; 03207 #ifndef HAVE_LIBSTROKE 03208 case F_Release: 03209 ReleaseMode (); 03210 break; 03211 #else 03212 case F_Release: 03213 if (mid_stroke) 03214 FinishStroke (); 03215 else 03216 ReleaseMode (); 03217 break; 03218 #endif 03219 case F_Remove: 03220 SetMode (REMOVE_MODE); 03221 break; 03222 case F_Rectangle: 03223 SetMode (RECTANGLE_MODE); 03224 break; 03225 case F_Rotate: 03226 SetMode (ROTATE_MODE); 03227 break; 03228 case F_Stroke: 03229 #ifdef HAVE_LIBSTROKE 03230 mid_stroke = true; 03231 StrokeBox.X1 = Crosshair.X; 03232 StrokeBox.Y1 = Crosshair.Y; 03233 break; 03234 #else 03235 /* Handle middle mouse button restarts of drawing mode. If not in 03236 | a drawing mode, middle mouse button will select objects. 03237 */ 03238 if (Settings.Mode == LINE_MODE 03239 && Crosshair.AttachedLine.State != STATE_FIRST) 03240 { 03241 SetMode (LINE_MODE); 03242 } 03243 else if (Settings.Mode == ARC_MODE 03244 && Crosshair.AttachedBox.State != STATE_FIRST) 03245 SetMode (ARC_MODE); 03246 else if (Settings.Mode == RECTANGLE_MODE 03247 && Crosshair.AttachedBox.State != STATE_FIRST) 03248 SetMode (RECTANGLE_MODE); 03249 else if (Settings.Mode == POLYGON_MODE 03250 && Crosshair.AttachedLine.State != STATE_FIRST) 03251 SetMode (POLYGON_MODE); 03252 else 03253 { 03254 SaveMode (); 03255 saved_mode = true; 03256 SetMode (ARROW_MODE); 03257 NotifyMode (); 03258 } 03259 break; 03260 #endif 03261 case F_Text: 03262 SetMode (TEXT_MODE); 03263 break; 03264 case F_Thermal: 03265 SetMode (THERMAL_MODE); 03266 break; 03267 case F_Via: 03268 SetMode (VIA_MODE); 03269 break; 03270 03271 case F_Restore: /* restore the last saved mode */ 03272 RestoreMode (); 03273 break; 03274 03275 case F_Save: /* save currently selected mode */ 03276 SaveMode (); 03277 break; 03278 } 03279 notify_crosshair_change (true); 03280 return 0; 03281 } 03282 03283 AFAIL (mode); 03284 } 03285 03286 /* --------------------------------------------------------------------------- */ 03287 03288 static const char removeselected_syntax[] = N_("RemoveSelected()"); 03289 03290 static const char removeselected_help[] = N_("Removes any selected objects."); 03291 03292 /* %start-doc actions RemoveSelected 03293 03294 %end-doc */ 03295 03296 static int 03297 ActionRemoveSelected (int argc, char **argv, Coord x, Coord y) 03298 { 03299 if (RemoveSelected ()) 03300 SetChangedFlag (true); 03301 return 0; 03302 } 03303 03304 /* --------------------------------------------------------------------------- */ 03305 03306 static const char renumber_syntax[] = N_("Renumber()\n" 03307 "Renumber(filename)"); 03308 03309 static const char renumber_help[] = 03310 N_("Renumber all elements. The changes will be recorded to filename\n" 03311 "for use in backannotating these changes to the schematic."); 03312 03313 /* %start-doc actions Renumber 03314 03315 %end-doc */ 03316 03317 static int 03318 ActionRenumber (int argc, char **argv, Coord x, Coord y) 03319 { 03320 bool changed = false; 03321 ElementType **element_list; 03322 ElementType **locked_element_list; 03323 unsigned int i, j, k, cnt, lock_cnt; 03324 unsigned int tmpi; 03325 size_t sz; 03326 char *tmps; 03327 char *name; 03328 FILE *out; 03329 static char * default_file = NULL; 03330 size_t cnt_list_sz = 100; 03331 struct _cnt_list 03332 { 03333 char *name; 03334 unsigned int cnt; 03335 } *cnt_list; 03336 char **was, **is, *pin; 03337 unsigned int c_cnt = 0; 03338 int unique, ok; 03339 int free_name = 0; 03340 03341 if (argc < 1) 03342 { 03343 /* 03344 * We deal with the case where name already exists in this 03345 * function so the GUI doesn't need to deal with it 03346 */ 03347 name = gui->fileselect (_("Save Renumber Annotation File As ..."), 03348 _("Choose a file to record the renumbering to.\n" 03349 "This file may be used to back annotate the\n" 03350 "change to the schematics.\n"), 03351 default_file, ".eco", "eco", 03352 0); 03353 03354 free_name = 1; 03355 } 03356 else 03357 name = argv[0]; 03358 03359 if (default_file) 03360 { 03361 free (default_file); 03362 default_file = NULL; 03363 } 03364 03365 if (name && *name) 03366 { 03367 default_file = strdup (name); 03368 } 03369 03370 if ((out = fopen (name, "r"))) 03371 { 03372 fclose (out); 03373 if (!gui->confirm_dialog (_("File exists! Ok to overwrite?"), 0)) 03374 { 03375 if (free_name && name) 03376 free (name); 03377 return 0; 03378 } 03379 } 03380 03381 if ((out = fopen (name, "w")) == NULL) 03382 { 03383 Message (_("Could not open %s\n"), name); 03384 if (free_name && name) 03385 free (name); 03386 return 1; 03387 } 03388 03389 if (free_name && name) 03390 free (name); 03391 03392 fprintf (out, "*COMMENT* PCB Annotation File\n"); 03393 fprintf (out, "*FILEVERSION* 20061031\n"); 03394 03395 /* 03396 * Make a first pass through all of the elements and sort them out 03397 * by location on the board. While here we also collect a list of 03398 * locked elements. 03399 * 03400 * We'll actually renumber things in the 2nd pass. 03401 */ 03402 element_list = (ElementType **)calloc (PCB->Data->ElementN, sizeof (ElementType *)); 03403 locked_element_list = (ElementType **)calloc (PCB->Data->ElementN, sizeof (ElementType *)); 03404 was = (char **)calloc (PCB->Data->ElementN, sizeof (char *)); 03405 is = (char **)calloc (PCB->Data->ElementN, sizeof (char *)); 03406 if (element_list == NULL || locked_element_list == NULL || was == NULL 03407 || is == NULL) 03408 { 03409 fprintf (stderr, "calloc() failed in %s\n", __FUNCTION__); 03410 exit (1); 03411 } 03412 03413 03414 cnt = 0; 03415 lock_cnt = 0; 03416 ELEMENT_LOOP (PCB->Data); 03417 { 03418 if (TEST_FLAG (LOCKFLAG, element->Name) || TEST_FLAG (LOCKFLAG, element)) 03419 { 03420 /* 03421 * add to the list of locked elements which we won't try to 03422 * renumber and whose reference designators are now reserved. 03423 */ 03424 pcb_fprintf (out, 03425 "*WARN* Element \"%s\" at %$md is locked and will not be renumbered.\n", 03426 UNKNOWN (NAMEONPCB_NAME (element)), element->MarkX, element->MarkY); 03427 locked_element_list[lock_cnt] = element; 03428 lock_cnt++; 03429 } 03430 03431 else 03432 { 03433 /* count of devices which will be renumbered */ 03434 cnt++; 03435 03436 /* search for correct position in the list */ 03437 i = 0; 03438 while (element_list[i] && element->MarkY > element_list[i]->MarkY) 03439 i++; 03440 03441 /* 03442 * We have found the position where we have the first element that 03443 * has the same Y value or a lower Y value. Now move forward if 03444 * needed through the X values 03445 */ 03446 while (element_list[i] 03447 && element->MarkY == element_list[i]->MarkY 03448 && element->MarkX > element_list[i]->MarkX) 03449 i++; 03450 03451 for (j = cnt - 1; j > i; j--) 03452 { 03453 element_list[j] = element_list[j - 1]; 03454 } 03455 element_list[i] = element; 03456 } 03457 } 03458 END_LOOP; 03459 03460 03461 /* 03462 * Now that the elements are sorted by board position, we go through 03463 * and renumber them. 03464 */ 03465 03466 /* 03467 * turn off the flag which requires unique names so it doesn't get 03468 * in our way. When we're done with the renumber we will have unique 03469 * names. 03470 */ 03471 unique = TEST_FLAG (UNIQUENAMEFLAG, PCB); 03472 CLEAR_FLAG (UNIQUENAMEFLAG, PCB); 03473 03474 cnt_list = (struct _cnt_list *)calloc (cnt_list_sz, sizeof (struct _cnt_list)); 03475 for (i = 0; i < cnt; i++) 03476 { 03477 /* If there is no refdes, maybe just spit out a warning */ 03478 if (NAMEONPCB_NAME (element_list[i])) 03479 { 03480 /* figure out the prefix */ 03481 tmps = strdup (NAMEONPCB_NAME (element_list[i])); 03482 j = 0; 03483 while (tmps[j] && (tmps[j] < '0' || tmps[j] > '9') 03484 && tmps[j] != '?') 03485 j++; 03486 tmps[j] = '\0'; 03487 03488 /* check the counter for this prefix */ 03489 for (j = 0; 03490 cnt_list[j].name && (strcmp (cnt_list[j].name, tmps) != 0) 03491 && j < cnt_list_sz; j++); 03492 03493 /* grow the list if needed */ 03494 if (j == cnt_list_sz) 03495 { 03496 cnt_list_sz += 100; 03497 cnt_list = (struct _cnt_list *)realloc (cnt_list, cnt_list_sz); 03498 if (cnt_list == NULL) 03499 { 03500 fprintf (stderr, _("realloc() failed in %s()\n"), __FUNCTION__); 03501 exit (1); 03502 } 03503 /* zero out the memory that we added */ 03504 for (tmpi = j; tmpi < cnt_list_sz; tmpi++) 03505 { 03506 cnt_list[tmpi].name = NULL; 03507 cnt_list[tmpi].cnt = 0; 03508 } 03509 } 03510 03511 /* 03512 * start a new counter if we don't have a counter for this 03513 * prefix 03514 */ 03515 if (!cnt_list[j].name) 03516 { 03517 cnt_list[j].name = strdup (tmps); 03518 cnt_list[j].cnt = 0; 03519 } 03520 03521 /* 03522 * check to see if the new refdes is already used by a 03523 * locked element 03524 */ 03525 do 03526 { 03527 ok = 1; 03528 cnt_list[j].cnt++; 03529 free (tmps); 03530 03531 /* space for the prefix plus 1 digit plus the '\0' */ 03532 sz = strlen (cnt_list[j].name) + 2; 03533 03534 /* and 1 more per extra digit needed to hold the number */ 03535 tmpi = cnt_list[j].cnt; 03536 while (tmpi > 10) 03537 { 03538 sz++; 03539 tmpi = tmpi / 10; 03540 } 03541 tmps = (char *)malloc (sz * sizeof (char)); 03542 sprintf (tmps, "%s%d", cnt_list[j].name, (int) cnt_list[j].cnt); 03543 03544 /* 03545 * now compare to the list of reserved (by locked 03546 * elements) names 03547 */ 03548 for (k = 0; k < lock_cnt; k++) 03549 { 03550 if (strcmp 03551 (UNKNOWN (NAMEONPCB_NAME (locked_element_list[k])), 03552 tmps) == 0) 03553 { 03554 ok = 0; 03555 break; 03556 } 03557 } 03558 03559 } 03560 while (!ok); 03561 03562 if (strcmp (tmps, NAMEONPCB_NAME (element_list[i])) != 0) 03563 { 03564 fprintf (out, "*RENAME* \"%s\" \"%s\"\n", 03565 NAMEONPCB_NAME (element_list[i]), tmps); 03566 03567 /* add this rename to our table of renames so we can update the netlist */ 03568 was[c_cnt] = strdup (NAMEONPCB_NAME (element_list[i])); 03569 is[c_cnt] = strdup (tmps); 03570 c_cnt++; 03571 03572 AddObjectToChangeNameUndoList (ELEMENT_TYPE, NULL, NULL, 03573 element_list[i], 03574 NAMEONPCB_NAME (element_list 03575 [i])); 03576 03577 ChangeObjectName (ELEMENT_TYPE, element_list[i], NULL, NULL, 03578 tmps); 03579 changed = true; 03580 03581 /* we don't free tmps in this case because it is used */ 03582 } 03583 else 03584 free (tmps); 03585 } 03586 else 03587 { 03588 pcb_fprintf (out, "*WARN* Element at %$md has no name.\n", 03589 element_list[i]->MarkX, element_list[i]->MarkY); 03590 } 03591 03592 } 03593 03594 fclose (out); 03595 03596 /* restore the unique flag setting */ 03597 if (unique) 03598 SET_FLAG (UNIQUENAMEFLAG, PCB); 03599 03600 if (changed) 03601 { 03602 03603 /* update the netlist */ 03604 AddNetlistLibToUndoList (&(PCB->NetlistLib)); 03605 03606 /* iterate over each net */ 03607 for (i = 0; i < PCB->NetlistLib.MenuN; i++) 03608 { 03609 03610 /* iterate over each pin on the net */ 03611 for (j = 0; j < PCB->NetlistLib.Menu[i].EntryN; j++) 03612 { 03613 03614 /* figure out the pin number part from strings like U3-21 */ 03615 tmps = strdup (PCB->NetlistLib.Menu[i].Entry[j].ListEntry); 03616 for (k = 0; tmps[k] && tmps[k] != '-'; k++); 03617 tmps[k] = '\0'; 03618 pin = tmps + k + 1; 03619 03620 /* iterate over the list of changed reference designators */ 03621 for (k = 0; k < c_cnt; k++) 03622 { 03623 /* 03624 * if the pin needs to change, change it and quit 03625 * searching in the list. 03626 */ 03627 if (strcmp (tmps, was[k]) == 0) 03628 { 03629 free (PCB->NetlistLib.Menu[i].Entry[j].ListEntry); 03630 PCB->NetlistLib.Menu[i].Entry[j].ListEntry = 03631 (char *)malloc ((strlen (is[k]) + strlen (pin) + 03632 2) * sizeof (char)); 03633 sprintf (PCB->NetlistLib.Menu[i].Entry[j].ListEntry, 03634 "%s-%s", is[k], pin); 03635 k = c_cnt; 03636 } 03637 03638 } 03639 free (tmps); 03640 } 03641 } 03642 for (k = 0; k < c_cnt; k++) 03643 { 03644 free (was[k]); 03645 free (is[k]); 03646 } 03647 03648 NetlistChanged (0); 03649 IncrementUndoSerialNumber (); 03650 SetChangedFlag (true); 03651 } 03652 03653 free (locked_element_list); 03654 free (element_list); 03655 free (cnt_list); 03656 free (is); 03657 free (was); 03658 return 0; 03659 } 03660 03661 03662 /* --------------------------------------------------------------------------- */ 03663 03664 static const char ripup_syntax[] = N_("RipUp(All|Selected|Element)"); 03665 03666 static const char ripup_help[] = 03667 N_("Ripup auto-routed tracks, or convert an element to parts."); 03668 03669 /* %start-doc actions RipUp 03670 03671 @table @code 03672 03673 @item All 03674 Removes all lines and vias which were created by the autorouter. 03675 03676 @item Selected 03677 Removes all selected lines and vias which were created by the 03678 autorouter. 03679 03680 @item Element 03681 Converts the element under the cursor to parts (vias and lines). Note 03682 that this uses the highest numbered paste buffer. 03683 03684 @end table 03685 03686 %end-doc */ 03687 03688 static int 03689 ActionRipUp (int argc, char **argv, Coord x, Coord y) 03690 { 03691 char *function = ARG (0); 03692 bool changed = false; 03693 03694 if (function) 03695 { 03696 switch (GetFunctionID (function)) 03697 { 03698 case F_All: 03699 ALLLINE_LOOP (PCB->Data); 03700 { 03701 if (TEST_FLAG (AUTOFLAG, line) && !TEST_FLAG (LOCKFLAG, line)) 03702 { 03703 RemoveObject (LINE_TYPE, layer, line, line); 03704 changed = true; 03705 } 03706 } 03707 ENDALL_LOOP; 03708 ALLARC_LOOP (PCB->Data); 03709 { 03710 if (TEST_FLAG (AUTOFLAG, arc) && !TEST_FLAG (LOCKFLAG, arc)) 03711 { 03712 RemoveObject (ARC_TYPE, layer, arc, arc); 03713 changed = true; 03714 } 03715 } 03716 ENDALL_LOOP; 03717 VIA_LOOP (PCB->Data); 03718 { 03719 if (TEST_FLAG (AUTOFLAG, via) && !TEST_FLAG (LOCKFLAG, via)) 03720 { 03721 RemoveObject (VIA_TYPE, via, via, via); 03722 changed = true; 03723 } 03724 } 03725 END_LOOP; 03726 03727 if (changed) 03728 { 03729 IncrementUndoSerialNumber (); 03730 SetChangedFlag (true); 03731 } 03732 break; 03733 case F_Selected: 03734 VISIBLELINE_LOOP (PCB->Data); 03735 { 03736 if (TEST_FLAGS (AUTOFLAG | SELECTEDFLAG, line) 03737 && !TEST_FLAG (LOCKFLAG, line)) 03738 { 03739 RemoveObject (LINE_TYPE, layer, line, line); 03740 changed = true; 03741 } 03742 } 03743 ENDALL_LOOP; 03744 if (PCB->ViaOn) 03745 VIA_LOOP (PCB->Data); 03746 { 03747 if (TEST_FLAGS (AUTOFLAG | SELECTEDFLAG, via) 03748 && !TEST_FLAG (LOCKFLAG, via)) 03749 { 03750 RemoveObject (VIA_TYPE, via, via, via); 03751 changed = true; 03752 } 03753 } 03754 END_LOOP; 03755 if (changed) 03756 { 03757 IncrementUndoSerialNumber (); 03758 SetChangedFlag (true); 03759 } 03760 break; 03761 case F_Element: 03762 { 03763 void *ptr1, *ptr2, *ptr3; 03764 03765 if (SearchScreen (Crosshair.X, Crosshair.Y, ELEMENT_TYPE, 03766 &ptr1, &ptr2, &ptr3) != NO_TYPE) 03767 { 03768 Note.Buffer = Settings.BufferNumber; 03769 SetBufferNumber (MAX_BUFFER - 1); 03770 ClearBuffer (PASTEBUFFER); 03771 CopyObjectToBuffer (PASTEBUFFER->Data, PCB->Data, 03772 ELEMENT_TYPE, ptr1, ptr2, ptr3); 03773 SmashBufferElement (PASTEBUFFER); 03774 PASTEBUFFER->X = 0; 03775 PASTEBUFFER->Y = 0; 03776 SaveUndoSerialNumber (); 03777 EraseObject (ELEMENT_TYPE, ptr1, ptr1); 03778 MoveObjectToRemoveUndoList (ELEMENT_TYPE, ptr1, ptr2, ptr3); 03779 RestoreUndoSerialNumber (); 03780 CopyPastebufferToLayout (0, 0); 03781 SetBufferNumber (Note.Buffer); 03782 SetChangedFlag (true); 03783 } 03784 } 03785 break; 03786 } 03787 } 03788 return 0; 03789 } 03790 03791 /* --------------------------------------------------------------------------- */ 03792 03793 static const char addrats_syntax[] = N_("AddRats(AllRats|SelectedRats|Close)"); 03794 03795 static const char addrats_help[] = 03796 N_("Add one or more rat lines to the board."); 03797 03798 /* %start-doc actions AddRats 03799 03800 @table @code 03801 03802 @item AllRats 03803 Create rat lines for all loaded nets that aren't already connected on 03804 with copper. 03805 03806 @item SelectedRats 03807 Similarly, but only add rat lines for nets connected to selected pins 03808 and pads. 03809 03810 @item Close 03811 Selects the shortest unselected rat on the board. 03812 03813 @end table 03814 03815 %end-doc */ 03816 03817 static int 03818 ActionAddRats (int argc, char **argv, Coord x, Coord y) 03819 { 03820 char *function = ARG (0); 03821 RatType *shorty; 03822 float len, small; 03823 03824 if (function) 03825 { 03826 if (Settings.RatWarn) 03827 ClearWarnings (); 03828 switch (GetFunctionID (function)) 03829 { 03830 case F_AllRats: 03831 if (AddAllRats (false, NULL)) 03832 SetChangedFlag (true); 03833 break; 03834 case F_SelectedRats: 03835 case F_Selected: 03836 if (AddAllRats (true, NULL)) 03837 SetChangedFlag (true); 03838 break; 03839 case F_Close: 03840 small = SQUARE (MAX_COORD); 03841 shorty = NULL; 03842 RAT_LOOP (PCB->Data); 03843 { 03844 if (TEST_FLAG (SELECTEDFLAG, line)) 03845 continue; 03846 len = SQUARE (line->Point1.X - line->Point2.X) + 03847 SQUARE (line->Point1.Y - line->Point2.Y); 03848 if (len < small) 03849 { 03850 small = len; 03851 shorty = line; 03852 } 03853 } 03854 END_LOOP; 03855 if (shorty) 03856 { 03857 AddObjectToFlagUndoList (RATLINE_TYPE, shorty, shorty, shorty); 03858 SET_FLAG (SELECTEDFLAG, shorty); 03859 DrawRat (shorty); 03860 Draw (); 03861 CenterDisplay ((shorty->Point2.X + shorty->Point1.X) / 2, 03862 (shorty->Point2.Y + shorty->Point1.Y) / 2, 03863 false); 03864 } 03865 break; 03866 } 03867 } 03868 return 0; 03869 } 03870 03871 /* --------------------------------------------------------------------------- */ 03872 03873 static const char delete_syntax[] = 03874 N_("Delete(Object|Selected)\n" 03875 "Delete(AllRats|SelectedRats)"); 03876 03877 static const char delete_help[] = N_("Delete stuff."); 03878 03879 /* %start-doc actions Delete 03880 03881 %end-doc */ 03882 03883 static int 03884 ActionDelete (int argc, char **argv, Coord x, Coord y) 03885 { 03886 char *function = ARG (0); 03887 int id = GetFunctionID (function); 03888 03889 Note.X = Crosshair.X; 03890 Note.Y = Crosshair.Y; 03891 03892 if (id == -1) /* no arg */ 03893 { 03894 if (RemoveSelected() == false) 03895 id = F_Object; 03896 } 03897 03898 switch (id) 03899 { 03900 case F_Object: 03901 SaveMode(); 03902 SetMode(REMOVE_MODE); 03903 NotifyMode(); 03904 RestoreMode(); 03905 break; 03906 case F_Selected: 03907 RemoveSelected(); 03908 break; 03909 case F_AllRats: 03910 if (DeleteRats (false)) 03911 SetChangedFlag (true); 03912 break; 03913 case F_SelectedRats: 03914 if (DeleteRats (true)) 03915 SetChangedFlag (true); 03916 break; 03917 } 03918 03919 return 0; 03920 } 03921 03922 /* --------------------------------------------------------------------------- */ 03923 03924 static const char deleterats_syntax[] = 03925 N_("DeleteRats(AllRats|Selected|SelectedRats)"); 03926 03927 static const char deleterats_help[] = N_("Delete rat lines."); 03928 03929 /* %start-doc actions DeleteRats 03930 03931 %end-doc */ 03932 03933 static int 03934 ActionDeleteRats (int argc, char **argv, Coord x, Coord y) 03935 { 03936 char *function = ARG (0); 03937 if (function) 03938 { 03939 if (Settings.RatWarn) 03940 ClearWarnings (); 03941 switch (GetFunctionID (function)) 03942 { 03943 case F_AllRats: 03944 if (DeleteRats (false)) 03945 SetChangedFlag (true); 03946 break; 03947 case F_SelectedRats: 03948 case F_Selected: 03949 if (DeleteRats (true)) 03950 SetChangedFlag (true); 03951 break; 03952 } 03953 } 03954 return 0; 03955 } 03956 03957 /* --------------------------------------------------------------------------- */ 03958 03959 static const char autoplace_syntax[] = N_("AutoPlaceSelected()"); 03960 03961 static const char autoplace_help[] = N_("Auto-place selected components."); 03962 03963 /* %start-doc actions AutoPlaceSelected 03964 03965 Attempts to re-arrange the selected components such that the nets 03966 connecting them are minimized. Note that you cannot undo this. 03967 03968 %end-doc */ 03969 03970 static int 03971 ActionAutoPlaceSelected (int argc, char **argv, Coord x, Coord y) 03972 { 03973 hid_action("Busy"); 03974 if (gui->confirm_dialog (_("Auto-placement can NOT be undone.\n" 03975 "Do you want to continue anyway?\n"), 0)) 03976 { 03977 if (AutoPlaceSelected ()) 03978 SetChangedFlag (true); 03979 } 03980 return 0; 03981 } 03982 03983 /* --------------------------------------------------------------------------- */ 03984 03985 static const char autoroute_syntax[] = N_("AutoRoute(AllRats|SelectedRats)"); 03986 03987 static const char autoroute_help[] = N_("Auto-route some or all rat lines."); 03988 03989 /* %start-doc actions AutoRoute 03990 03991 @table @code 03992 03993 @item AllRats 03994 Attempt to autoroute all rats. 03995 03996 @item SelectedRats 03997 Attempt to autoroute the selected rats. 03998 03999 @end table 04000 04001 Before autorouting, it's important to set up a few things. First, 04002 make sure any layers you aren't using are disabled, else the 04003 autorouter may use them. Next, make sure the current line and via 04004 styles are set accordingly. Last, make sure "new lines clear 04005 polygons" is set, in case you eventually want to add a copper pour. 04006 04007 Autorouting takes a while. During this time, the program may not be 04008 responsive. 04009 04010 %end-doc */ 04011 04012 static int 04013 ActionAutoRoute (int argc, char **argv, Coord x, Coord y) 04014 { 04015 char *function = ARG (0); 04016 hid_action("Busy"); 04017 if (function) /* one parameter */ 04018 { 04019 switch (GetFunctionID (function)) 04020 { 04021 case F_AllRats: 04022 if (AutoRoute (false)) 04023 SetChangedFlag (true); 04024 break; 04025 case F_SelectedRats: 04026 case F_Selected: 04027 if (AutoRoute (true)) 04028 SetChangedFlag (true); 04029 break; 04030 } 04031 } 04032 return 0; 04033 } 04034 04035 /* --------------------------------------------------------------------------- */ 04036 04037 static const char markcrosshair_syntax[] = 04038 N_("MarkCrosshair()\n" 04039 "MarkCrosshair(Center)"); 04040 04041 static const char markcrosshair_help[] = N_("Set/Reset the Crosshair mark."); 04042 04043 /* %start-doc actions MarkCrosshair 04044 04045 The ``mark'' is a small X-shaped target on the display which is 04046 treated like a second origin (the normal origin is the upper let 04047 corner of the board). The GUI will display a second set of 04048 coordinates for this mark, which tells you how far you are from it. 04049 04050 If no argument is given, the mark is toggled - disabled if it was 04051 enabled, or enabled at the current cursor position of disabled. If 04052 the @code{Center} argument is given, the mark is moved to the current 04053 cursor location. 04054 04055 %end-doc */ 04056 04057 static int 04058 ActionMarkCrosshair (int argc, char **argv, Coord x, Coord y) 04059 { 04060 char *function = ARG (0); 04061 if (!function || !*function) 04062 { 04063 if (Marked.status) 04064 { 04065 notify_mark_change (false); 04066 Marked.status = false; 04067 notify_mark_change (true); 04068 } 04069 else 04070 { 04071 notify_mark_change (false); 04072 Marked.status = false; 04073 Marked.status = true; 04074 Marked.X = Crosshair.X; 04075 Marked.Y = Crosshair.Y; 04076 notify_mark_change (true); 04077 } 04078 } 04079 else if (GetFunctionID (function) == F_Center) 04080 { 04081 notify_mark_change (false); 04082 Marked.status = true; 04083 Marked.X = Crosshair.X; 04084 Marked.Y = Crosshair.Y; 04085 notify_mark_change (true); 04086 } 04087 return 0; 04088 } 04089 04090 /* --------------------------------------------------------------------------- */ 04091 04092 static const char changesize_syntax[] = 04093 N_("ChangeSize(Object, delta)\n" 04094 "ChangeSize(SelectedObjects|Selected, delta)\n" 04095 "ChangeSize(SelectedLines|SelectedPins|SelectedVias, delta)\n" 04096 "ChangeSize(SelectedPads|SelectedTexts|SelectedNames, delta)\n" 04097 "ChangeSize(SelectedElements, delta)"); 04098 04099 static const char changesize_help[] = N_("Changes the size of objects."); 04100 04101 /* %start-doc actions ChangeSize 04102 04103 For lines and arcs, this changes the width. For pins and vias, this 04104 changes the overall diameter of the copper annulus. For pads, this 04105 changes the width and, indirectly, the length. For texts and names, 04106 this changes the scaling factor. For elements, this changes the width 04107 of the silk layer lines and arcs for this element. 04108 04109 %end-doc */ 04110 04111 static int 04112 ActionChangeSize (int argc, char **argv, Coord x, Coord y) 04113 { 04114 char *function = ARG (0); 04115 char *delta = ARG (1); 04116 char *units = ARG (2); 04117 bool absolute; /* indicates if absolute size is given */ 04118 Coord value; 04119 04120 if (function && delta) 04121 { 04122 value = GetValue (delta, units, &absolute); 04123 if (value == 0) 04124 value = delta[0] == '-' ? -Settings.increments->size 04125 : Settings.increments->size; 04126 switch (GetFunctionID (function)) 04127 { 04128 case F_Object: 04129 { 04130 int type; 04131 void *ptr1, *ptr2, *ptr3; 04132 04133 if ((type = 04134 SearchScreen (Crosshair.X, Crosshair.Y, CHANGESIZE_TYPES, 04135 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 04136 if (TEST_FLAG (LOCKFLAG, (PinType *) ptr2)) 04137 Message (_("Sorry, the object is locked\n")); 04138 if (ChangeObjectSize (type, ptr1, ptr2, ptr3, value, absolute)) 04139 SetChangedFlag (true); 04140 break; 04141 } 04142 04143 case F_SelectedVias: 04144 if (ChangeSelectedSize (VIA_TYPE, value, absolute)) 04145 SetChangedFlag (true); 04146 break; 04147 04148 case F_SelectedPins: 04149 if (ChangeSelectedSize (PIN_TYPE, value, absolute)) 04150 SetChangedFlag (true); 04151 break; 04152 04153 case F_SelectedPads: 04154 if (ChangeSelectedSize (PAD_TYPE, value, absolute)) 04155 SetChangedFlag (true); 04156 break; 04157 04158 case F_SelectedArcs: 04159 if (ChangeSelectedSize (ARC_TYPE, value, absolute)) 04160 SetChangedFlag (true); 04161 break; 04162 04163 case F_SelectedLines: 04164 if (ChangeSelectedSize (LINE_TYPE, value, absolute)) 04165 SetChangedFlag (true); 04166 break; 04167 04168 case F_SelectedTexts: 04169 if (ChangeSelectedSize (TEXT_TYPE, value, absolute)) 04170 SetChangedFlag (true); 04171 break; 04172 04173 case F_SelectedNames: 04174 if (ChangeSelectedSize (ELEMENTNAME_TYPE, value, absolute)) 04175 SetChangedFlag (true); 04176 break; 04177 04178 case F_SelectedElements: 04179 if (ChangeSelectedSize (ELEMENT_TYPE, value, absolute)) 04180 SetChangedFlag (true); 04181 break; 04182 04183 case F_Selected: 04184 case F_SelectedObjects: 04185 if (ChangeSelectedSize (CHANGESIZE_TYPES, value, absolute)) 04186 SetChangedFlag (true); 04187 break; 04188 } 04189 } 04190 return 0; 04191 } 04192 04193 /* --------------------------------------------------------------------------- */ 04194 04195 static const char changedrillsize_syntax[] = 04196 N_("ChangeDrillSize(Object, delta)\n" 04197 "ChangeDrillSize(SelectedPins|SelectedVias|Selected|SelectedObjects, delta)"); 04198 04199 static const char changedrillsize_help[] = 04200 N_("Changes the drilling hole size of objects."); 04201 04202 /* %start-doc actions ChangeDrillSize 04203 04204 %end-doc */ 04205 04206 static int 04207 ActionChange2ndSize (int argc, char **argv, Coord x, Coord y) 04208 { 04209 char *function = ARG (0); 04210 char *delta = ARG (1); 04211 char *units = ARG (2); 04212 bool absolute; 04213 Coord value; 04214 04215 if (function && delta) 04216 { 04217 value = GetValue (delta, units, &absolute); 04218 switch (GetFunctionID (function)) 04219 { 04220 case F_Object: 04221 { 04222 int type; 04223 void *ptr1, *ptr2, *ptr3; 04224 04225 gui->get_coords (_("Select an Object"), &x, &y); 04226 if ((type = 04227 SearchScreen (x, y, CHANGE2NDSIZE_TYPES, 04228 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 04229 if (ChangeObject2ndSize 04230 (type, ptr1, ptr2, ptr3, value, absolute, true)) 04231 SetChangedFlag (true); 04232 break; 04233 } 04234 04235 case F_SelectedVias: 04236 if (ChangeSelected2ndSize (VIA_TYPE, value, absolute)) 04237 SetChangedFlag (true); 04238 break; 04239 04240 case F_SelectedPins: 04241 if (ChangeSelected2ndSize (PIN_TYPE, value, absolute)) 04242 SetChangedFlag (true); 04243 break; 04244 case F_Selected: 04245 case F_SelectedObjects: 04246 if (ChangeSelected2ndSize (PIN_TYPES, value, absolute)) 04247 SetChangedFlag (true); 04248 break; 04249 } 04250 } 04251 return 0; 04252 } 04253 04254 /* --------------------------------------------------------------------------- */ 04255 04256 static const char changeclearsize_syntax[] = 04257 N_("ChangeClearSize(Object, delta)\n" 04258 "ChangeClearSize(SelectedPins|SelectedPads|SelectedVias, delta)\n" 04259 "ChangeClearSize(SelectedLines|SelectedArcs, delta\n" 04260 "ChangeClearSize(Selected|SelectedObjects, delta)"); 04261 04262 static const char changeclearsize_help[] = 04263 N_("Changes the clearance size of objects."); 04264 04265 /* %start-doc actions ChangeClearSize 04266 04267 If the solder mask is currently showing, this action changes the 04268 solder mask clearance. If the mask is not showing, this action 04269 changes the polygon clearance. 04270 04271 %end-doc */ 04272 04273 static int 04274 ActionChangeClearSize (int argc, char **argv, Coord x, Coord y) 04275 { 04276 char *function = ARG (0); 04277 char *delta = ARG (1); 04278 char *units = ARG (2); 04279 bool absolute; 04280 Coord value; 04281 04282 if (function && delta) 04283 { 04284 value = 2 * GetValue (delta, units, &absolute); 04285 if (value == 0) 04286 value = delta[0] == '-' ? -Settings.increments->clear 04287 : Settings.increments->clear; 04288 switch (GetFunctionID (function)) 04289 { 04290 case F_Object: 04291 { 04292 int type; 04293 void *ptr1, *ptr2, *ptr3; 04294 04295 gui->get_coords (_("Select an Object"), &x, &y); 04296 if ((type = 04297 SearchScreen (x, y, 04298 CHANGECLEARSIZE_TYPES, &ptr1, &ptr2, 04299 &ptr3)) != NO_TYPE) 04300 if (ChangeObjectClearSize (type, ptr1, ptr2, ptr3, value, absolute)) 04301 SetChangedFlag (true); 04302 break; 04303 } 04304 case F_SelectedVias: 04305 if (ChangeSelectedClearSize (VIA_TYPE, value, absolute)) 04306 SetChangedFlag (true); 04307 break; 04308 case F_SelectedPads: 04309 if (ChangeSelectedClearSize (PAD_TYPE, value, absolute)) 04310 SetChangedFlag (true); 04311 break; 04312 case F_SelectedPins: 04313 if (ChangeSelectedClearSize (PIN_TYPE, value, absolute)) 04314 SetChangedFlag (true); 04315 break; 04316 case F_SelectedLines: 04317 if (ChangeSelectedClearSize (LINE_TYPE, value, absolute)) 04318 SetChangedFlag (true); 04319 break; 04320 case F_SelectedArcs: 04321 if (ChangeSelectedClearSize (ARC_TYPE, value, absolute)) 04322 SetChangedFlag (true); 04323 break; 04324 case F_Selected: 04325 case F_SelectedObjects: 04326 if (ChangeSelectedClearSize (CHANGECLEARSIZE_TYPES, value, absolute)) 04327 SetChangedFlag (true); 04328 break; 04329 } 04330 } 04331 return 0; 04332 } 04333 04334 /* --------------------------------------------------------------------------- */ 04335 04336 static const char minmaskgap_syntax[] = 04337 N_("MinMaskGap(delta)\n" 04338 "MinMaskGap(Selected, delta)"); 04339 04340 static const char minmaskgap_help[] = 04341 N_("Ensures the mask is a minimum distance from pins and pads."); 04342 04343 /* %start-doc actions MinMaskGap 04344 04345 Checks all specified pins and/or pads, and increases the mask if 04346 needed to ensure a minimum distance between the pin or pad edge and 04347 the mask edge. 04348 04349 %end-doc */ 04350 04351 static int 04352 ActionMinMaskGap (int argc, char **argv, Coord x, Coord y) 04353 { 04354 char *function = ARG (0); 04355 char *delta = ARG (1); 04356 char *units = ARG (2); 04357 bool absolute; 04358 Coord value; 04359 Coord thickness; 04360 int flags; 04361 04362 if (!function) 04363 return 1; 04364 if (strcasecmp (function, "Selected") == 0) 04365 flags = SELECTEDFLAG; 04366 else 04367 { 04368 units = delta; 04369 delta = function; 04370 flags = 0; 04371 } 04372 value = 2 * GetValue (delta, units, &absolute); 04373 04374 SaveUndoSerialNumber (); 04375 ELEMENT_LOOP (PCB->Data); 04376 { 04377 PIN_LOOP (element); 04378 { 04379 if (!TEST_FLAGS (flags, pin) || ! pin->Mask) continue; 04380 04381 thickness = pin->DrillingHole; 04382 04383 if (pin->Thickness > thickness) thickness = pin->Thickness; 04384 04385 thickness += value; 04386 04387 if (pin->Mask < thickness) 04388 { 04389 ChangeObjectMaskSize (PIN_TYPE, element, pin, 0, thickness, 1); 04390 RestoreUndoSerialNumber (); 04391 } 04392 } 04393 END_LOOP; 04394 PAD_LOOP (element); 04395 { 04396 if (!TEST_FLAGS (flags, pad) || ! pad->Mask) 04397 continue; 04398 if (pad->Mask < pad->Thickness + value) 04399 { 04400 ChangeObjectMaskSize (PAD_TYPE, element, pad, 0, 04401 pad->Thickness + value, 1); 04402 RestoreUndoSerialNumber (); 04403 } 04404 } 04405 END_LOOP; 04406 } 04407 END_LOOP; 04408 VIA_LOOP (PCB->Data); 04409 { 04410 if (!TEST_FLAGS (flags, via) || ! via->Mask) 04411 continue; 04412 04413 thickness = via->DrillingHole; 04414 if (via->Thickness > thickness) 04415 thickness = via->Thickness; 04416 thickness += value; 04417 04418 if (via->Mask < thickness) 04419 { 04420 ChangeObjectMaskSize (VIA_TYPE, via, 0, 0, thickness, 1); 04421 RestoreUndoSerialNumber (); 04422 } 04423 } 04424 END_LOOP; 04425 RestoreUndoSerialNumber (); 04426 IncrementUndoSerialNumber (); 04427 return 0; 04428 } 04429 04430 /* --------------------------------------------------------------------------- */ 04431 04432 static const char mincleargap_syntax[] = 04433 N_("MinClearGap(delta)\n" 04434 "MinClearGap(Selected, delta)"); 04435 04436 static const char mincleargap_help[] = 04437 N_("Ensures that polygons are a minimum distance from objects."); 04438 04439 /* %start-doc actions MinClearGap 04440 04441 Checks all specified objects, and increases the polygon clearance if 04442 needed to ensure a minimum distance between their edges and the 04443 polygon edges. 04444 04445 %end-doc */ 04446 04447 static int 04448 ActionMinClearGap (int argc, char **argv, Coord x, Coord y) 04449 { 04450 char *function = ARG (0); 04451 char *delta = ARG (1); 04452 char *units = ARG (2); 04453 bool absolute; 04454 Coord value; 04455 int flags; 04456 04457 if (!function) 04458 return 1; 04459 if (strcasecmp (function, "Selected") == 0) 04460 flags = SELECTEDFLAG; 04461 else 04462 { 04463 units = delta; 04464 delta = function; 04465 flags = 0; 04466 } 04467 value = 2 * GetValue (delta, units, &absolute); 04468 04469 SaveUndoSerialNumber (); 04470 ELEMENT_LOOP (PCB->Data); 04471 { 04472 PIN_LOOP (element); 04473 { 04474 if (!TEST_FLAGS (flags, pin)) 04475 continue; 04476 if (pin->Clearance < value) 04477 { 04478 ChangeObjectClearSize (PIN_TYPE, element, pin, 0, 04479 value, 1); 04480 RestoreUndoSerialNumber (); 04481 } 04482 } 04483 END_LOOP; 04484 PAD_LOOP (element); 04485 { 04486 if (!TEST_FLAGS (flags, pad)) 04487 continue; 04488 if (pad->Clearance < value) 04489 { 04490 ChangeObjectClearSize (PAD_TYPE, element, pad, 0, 04491 value, 1); 04492 RestoreUndoSerialNumber (); 04493 } 04494 } 04495 END_LOOP; 04496 } 04497 END_LOOP; 04498 VIA_LOOP (PCB->Data); 04499 { 04500 if (!TEST_FLAGS (flags, via)) 04501 continue; 04502 if (via->Clearance < value) 04503 { 04504 ChangeObjectClearSize (VIA_TYPE, via, 0, 0, value, 1); 04505 RestoreUndoSerialNumber (); 04506 } 04507 } 04508 END_LOOP; 04509 ALLLINE_LOOP (PCB->Data); 04510 { 04511 if (!TEST_FLAGS (flags, line)) 04512 continue; 04513 if (line->Clearance < value) 04514 { 04515 ChangeObjectClearSize (LINE_TYPE, layer, line, 0, value, 1); 04516 RestoreUndoSerialNumber (); 04517 } 04518 } 04519 ENDALL_LOOP; 04520 ALLARC_LOOP (PCB->Data); 04521 { 04522 if (!TEST_FLAGS (flags, arc)) 04523 continue; 04524 if (arc->Clearance < value) 04525 { 04526 ChangeObjectClearSize (ARC_TYPE, layer, arc, 0, value, 1); 04527 RestoreUndoSerialNumber (); 04528 } 04529 } 04530 ENDALL_LOOP; 04531 RestoreUndoSerialNumber (); 04532 IncrementUndoSerialNumber (); 04533 return 0; 04534 } 04535 04536 /* --------------------------------------------------------------------------- */ 04537 04538 static const char changepinname_syntax[] = 04539 N_("ChangePinName(ElementName,PinNumber,PinName)"); 04540 04541 static const char changepinname_help[] = 04542 N_("Sets the name of a specific pin on a specific element."); 04543 04544 /* %start-doc actions ChangePinName 04545 04546 This can be especially useful for annotating pin names from a 04547 schematic to the layout without requiring knowledge of the pcb file 04548 format. 04549 04550 @example 04551 ChangePinName(U3, 7, VCC) 04552 @end example 04553 04554 %end-doc */ 04555 04556 static int 04557 ActionChangePinName (int argc, char **argv, Coord x, Coord y) 04558 { 04559 int changed = 0; 04560 char *refdes, *pinnum, *pinname; 04561 04562 if (argc != 3) 04563 { 04564 AFAIL (changepinname); 04565 } 04566 04567 refdes = argv[0]; 04568 pinnum = argv[1]; 04569 pinname = argv[2]; 04570 04571 ELEMENT_LOOP (PCB->Data); 04572 { 04573 if (NSTRCMP (refdes, NAMEONPCB_NAME (element)) == 0) 04574 { 04575 PIN_LOOP (element); 04576 { 04577 if (NSTRCMP (pinnum, pin->Number) == 0) 04578 { 04579 AddObjectToChangeNameUndoList (PIN_TYPE, NULL, NULL, 04580 pin, pin->Name); 04581 /* 04582 * Note: we can't free() pin->Name first because 04583 * it is used in the undo list 04584 */ 04585 pin->Name = strdup (pinname); 04586 SetChangedFlag (true); 04587 changed = 1; 04588 } 04589 } 04590 END_LOOP; 04591 04592 PAD_LOOP (element); 04593 { 04594 if (NSTRCMP (pinnum, pad->Number) == 0) 04595 { 04596 AddObjectToChangeNameUndoList (PAD_TYPE, NULL, NULL, 04597 pad, pad->Name); 04598 /* 04599 * Note: we can't free() pad->Name first because 04600 * it is used in the undo list 04601 */ 04602 pad->Name = strdup (pinname); 04603 SetChangedFlag (true); 04604 changed = 1; 04605 } 04606 } 04607 END_LOOP; 04608 } 04609 } 04610 END_LOOP; 04611 /* 04612 * done with our action so increment the undo # if we actually 04613 * changed anything 04614 */ 04615 if (changed) 04616 { 04617 if (defer_updates) 04618 defer_needs_update = 1; 04619 else 04620 { 04621 IncrementUndoSerialNumber (); 04622 gui->invalidate_all (); 04623 } 04624 } 04625 04626 return 0; 04627 } 04628 04629 /* --------------------------------------------------------------------------- */ 04630 04631 static const char changename_syntax[] = 04632 N_("ChangeName(Object)\n" 04633 "ChangeName(Layout|Layer)"); 04634 04635 static const char changename_help[] = N_("Sets the name of objects."); 04636 04637 /* %start-doc actions ChangeName 04638 04639 @table @code 04640 04641 @item Object 04642 Changes the name of the element under the cursor. 04643 04644 @item Layout 04645 Changes the name of the layout. This is printed on the fab drawings. 04646 04647 @item Layer 04648 Changes the name of the currently active layer. 04649 04650 @end table 04651 04652 %end-doc */ 04653 04654 int 04655 ActionChangeName (int argc, char **argv, Coord x, Coord y) 04656 { 04657 char *function = ARG (0); 04658 char *name; 04659 04660 if (function) 04661 { 04662 switch (GetFunctionID (function)) 04663 { 04664 /* change the name of an object */ 04665 case F_Object: 04666 { 04667 int type; 04668 void *ptr1, *ptr2, *ptr3; 04669 04670 gui->get_coords (_("Select an Object"), &x, &y); 04671 if ((type = 04672 SearchScreen (x, y, CHANGENAME_TYPES, 04673 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 04674 { 04675 SaveUndoSerialNumber (); 04676 if (QueryInputAndChangeObjectName (type, ptr1, ptr2, ptr3)) 04677 { 04678 SetChangedFlag (true); 04679 if (type == ELEMENT_TYPE) 04680 { 04681 RubberbandType *ptr; 04682 int i; 04683 04684 RestoreUndoSerialNumber (); 04685 Crosshair.AttachedObject.RubberbandN = 0; 04686 LookupRatLines (type, ptr1, ptr2, ptr3); 04687 ptr = Crosshair.AttachedObject.Rubberband; 04688 for (i = 0; i < Crosshair.AttachedObject.RubberbandN; 04689 i++, ptr++) 04690 { 04691 if (PCB->RatOn) 04692 EraseRat ((RatType *) ptr->Line); 04693 MoveObjectToRemoveUndoList (RATLINE_TYPE, 04694 ptr->Line, ptr->Line, 04695 ptr->Line); 04696 } 04697 IncrementUndoSerialNumber (); 04698 Draw (); 04699 } 04700 } 04701 } 04702 break; 04703 } 04704 04705 /* change the layout's name */ 04706 case F_Layout: 04707 name = 04708 gui->prompt_for (_("Enter the layout name:"), EMPTY (PCB->Name)); 04709 /* NB: ChangeLayoutName takes ownership of the passed memory */ 04710 if (name && ChangeLayoutName (name)) 04711 SetChangedFlag (true); 04712 break; 04713 04714 /* change the name of the active layer */ 04715 case F_Layer: 04716 name = gui->prompt_for (_("Enter the layer name:"), 04717 EMPTY (CURRENT->Name)); 04718 /* NB: ChangeLayerName takes ownership of the passed memory */ 04719 if (name && ChangeLayerName (CURRENT, name)) 04720 SetChangedFlag (true); 04721 break; 04722 } 04723 } 04724 return 0; 04725 } 04726 04727 04728 /* --------------------------------------------------------------------------- */ 04729 04730 static const char morphpolygon_syntax[] = N_("MorphPolygon(Object|Selected)"); 04731 04732 static const char morphpolygon_help[] = 04733 N_("Converts dead polygon islands into separate polygons."); 04734 04735 /* %start-doc actions MorphPolygon 04736 04737 If a polygon is divided into unconnected "islands", you can use 04738 this command to convert the otherwise disappeared islands into 04739 separate polygons. Be sure the cursor is over a portion of the 04740 polygon that remains visible. Very small islands that may flake 04741 off are automatically deleted. 04742 04743 %end-doc */ 04744 04745 static int 04746 ActionMorphPolygon (int argc, char **argv, Coord x, Coord y) 04747 { 04748 char *function = ARG (0); 04749 if (function) 04750 { 04751 switch (GetFunctionID (function)) 04752 { 04753 case F_Object: 04754 { 04755 int type; 04756 void *ptr1, *ptr2, *ptr3; 04757 04758 gui->get_coords (_("Select an Object"), &x, &y); 04759 if ((type = SearchScreen (x, y, POLYGON_TYPE, 04760 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 04761 { 04762 MorphPolygon ((LayerType *) ptr1, (PolygonType *) ptr3); 04763 Draw (); 04764 IncrementUndoSerialNumber (); 04765 } 04766 break; 04767 } 04768 case F_Selected: 04769 case F_SelectedObjects: 04770 ALLPOLYGON_LOOP (PCB->Data); 04771 { 04772 if (TEST_FLAG (SELECTEDFLAG, polygon)) 04773 MorphPolygon (layer, polygon); 04774 } 04775 ENDALL_LOOP; 04776 Draw (); 04777 IncrementUndoSerialNumber (); 04778 break; 04779 } 04780 } 04781 return 0; 04782 } 04783 04784 /* --------------------------------------------------------------------------- */ 04785 04786 static const char togglehidename_syntax[] = 04787 N_("ToggleHideName(Object|SelectedElements)"); 04788 04789 static const char togglehidename_help[] = 04790 N_("Toggles the visibility of element names."); 04791 04792 /* %start-doc actions ToggleHideName 04793 04794 If names are hidden you won't see them on the screen and they will not 04795 appear on the silk layer when you print the layout. 04796 04797 %end-doc */ 04798 04799 static int 04800 ActionToggleHideName (int argc, char **argv, Coord x, Coord y) 04801 { 04802 char *function = ARG (0); 04803 if (function && PCB->ElementOn) 04804 { 04805 switch (GetFunctionID (function)) 04806 { 04807 case F_Object: 04808 { 04809 int type; 04810 void *ptr1, *ptr2, *ptr3; 04811 04812 gui->get_coords (_("Select an Object"), &x, &y); 04813 if ((type = SearchScreen (x, y, ELEMENT_TYPE, 04814 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 04815 { 04816 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr3); 04817 EraseElementName ((ElementType *) ptr2); 04818 TOGGLE_FLAG (HIDENAMEFLAG, (ElementType *) ptr2); 04819 DrawElementName ((ElementType *) ptr2); 04820 Draw (); 04821 IncrementUndoSerialNumber (); 04822 } 04823 break; 04824 } 04825 case F_SelectedElements: 04826 case F_Selected: 04827 { 04828 bool changed = false; 04829 ELEMENT_LOOP (PCB->Data); 04830 { 04831 if ((TEST_FLAG (SELECTEDFLAG, element) || 04832 TEST_FLAG (SELECTEDFLAG, 04833 &NAMEONPCB_TEXT (element))) 04834 && (FRONT (element) || PCB->InvisibleObjectsOn)) 04835 { 04836 AddObjectToFlagUndoList (ELEMENT_TYPE, element, 04837 element, element); 04838 EraseElementName (element); 04839 TOGGLE_FLAG (HIDENAMEFLAG, element); 04840 DrawElementName (element); 04841 changed = true; 04842 } 04843 } 04844 END_LOOP; 04845 if (changed) 04846 { 04847 Draw (); 04848 IncrementUndoSerialNumber (); 04849 } 04850 } 04851 } 04852 } 04853 return 0; 04854 } 04855 04856 /* --------------------------------------------------------------------------- */ 04857 04858 static const char changejoin_syntax[] = 04859 N_("ChangeJoin(ToggleObject|SelectedLines|SelectedArcs|Selected)"); 04860 04861 static const char changejoin_help[] = 04862 N_("Changes the join (clearance through polygons) of objects."); 04863 04864 /* %start-doc actions ChangeJoin 04865 04866 The join flag determines whether a line or arc, drawn to intersect a 04867 polygon, electrically connects to the polygon or not. When joined, 04868 the line/arc is simply drawn over the polygon, making an electrical 04869 connection. When not joined, a gap is drawn between the line and the 04870 polygon, insulating them from each other. 04871 04872 %end-doc */ 04873 04874 static int 04875 ActionChangeJoin (int argc, char **argv, Coord x, Coord y) 04876 { 04877 char *function = ARG (0); 04878 if (function) 04879 { 04880 switch (GetFunctionID (function)) 04881 { 04882 case F_ToggleObject: 04883 case F_Object: 04884 { 04885 int type; 04886 void *ptr1, *ptr2, *ptr3; 04887 04888 gui->get_coords (_("Select an Object"), &x, &y); 04889 if ((type = 04890 SearchScreen (x, y, CHANGEJOIN_TYPES, 04891 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 04892 if (ChangeObjectJoin (type, ptr1, ptr2, ptr3)) 04893 SetChangedFlag (true); 04894 break; 04895 } 04896 04897 case F_SelectedLines: 04898 if (ChangeSelectedJoin (LINE_TYPE)) 04899 SetChangedFlag (true); 04900 break; 04901 04902 case F_SelectedArcs: 04903 if (ChangeSelectedJoin (ARC_TYPE)) 04904 SetChangedFlag (true); 04905 break; 04906 04907 case F_Selected: 04908 case F_SelectedObjects: 04909 if (ChangeSelectedJoin (CHANGEJOIN_TYPES)) 04910 SetChangedFlag (true); 04911 break; 04912 } 04913 } 04914 return 0; 04915 } 04916 04917 /* --------------------------------------------------------------------------- */ 04918 04919 static const char changesquare_syntax[] = 04920 N_("ChangeSquare(ToggleObject)\n" 04921 "ChangeSquare(SelectedElements|SelectedPins)\n" 04922 "ChangeSquare(Selected|SelectedObjects)"); 04923 04924 static const char changesquare_help[] = 04925 N_("Changes the square flag of pins and pads."); 04926 04927 /* %start-doc actions ChangeSquare 04928 04929 Note that @code{Pins} means both pins and pads. 04930 04931 @pinshapes 04932 04933 %end-doc */ 04934 04935 static int 04936 ActionChangeSquare (int argc, char **argv, Coord x, Coord y) 04937 { 04938 char *function = ARG (0); 04939 if (function) 04940 { 04941 switch (GetFunctionID (function)) 04942 { 04943 case F_ToggleObject: 04944 case F_Object: 04945 { 04946 int type; 04947 void *ptr1, *ptr2, *ptr3; 04948 04949 gui->get_coords (_("Select an Object"), &x, &y); 04950 if ((type = 04951 SearchScreen (x, y, CHANGESQUARE_TYPES, 04952 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 04953 if (ChangeObjectSquare (type, ptr1, ptr2, ptr3)) 04954 SetChangedFlag (true); 04955 break; 04956 } 04957 04958 case F_SelectedElements: 04959 if (ChangeSelectedSquare (ELEMENT_TYPE)) 04960 SetChangedFlag (true); 04961 break; 04962 04963 case F_SelectedPins: 04964 if (ChangeSelectedSquare (PIN_TYPE | PAD_TYPE)) 04965 SetChangedFlag (true); 04966 break; 04967 04968 case F_Selected: 04969 case F_SelectedObjects: 04970 if (ChangeSelectedSquare (PIN_TYPE | PAD_TYPE)) 04971 SetChangedFlag (true); 04972 break; 04973 } 04974 } 04975 return 0; 04976 } 04977 04978 /* --------------------------------------------------------------------------- */ 04979 04980 static const char setsquare_syntax[] = 04981 N_("SetSquare(ToggleObject|SelectedElements|SelectedPins)"); 04982 04983 static const char setsquare_help[] = N_("sets the square-flag of objects."); 04984 04985 /* %start-doc actions SetSquare 04986 04987 Note that @code{Pins} means pins and pads. 04988 04989 @pinshapes 04990 04991 %end-doc */ 04992 04993 static int 04994 ActionSetSquare (int argc, char **argv, Coord x, Coord y) 04995 { 04996 char *function = ARG (0); 04997 if (function && *function) 04998 { 04999 switch (GetFunctionID (function)) 05000 { 05001 case F_ToggleObject: 05002 case F_Object: 05003 { 05004 int type; 05005 void *ptr1, *ptr2, *ptr3; 05006 05007 gui->get_coords (_("Select an Object"), &x, &y); 05008 if ((type = 05009 SearchScreen (x, y, CHANGESQUARE_TYPES, 05010 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 05011 if (SetObjectSquare (type, ptr1, ptr2, ptr3)) 05012 SetChangedFlag (true); 05013 break; 05014 } 05015 05016 case F_SelectedElements: 05017 if (SetSelectedSquare (ELEMENT_TYPE)) 05018 SetChangedFlag (true); 05019 break; 05020 05021 case F_SelectedPins: 05022 if (SetSelectedSquare (PIN_TYPE | PAD_TYPE)) 05023 SetChangedFlag (true); 05024 break; 05025 05026 case F_Selected: 05027 case F_SelectedObjects: 05028 if (SetSelectedSquare (PIN_TYPE | PAD_TYPE)) 05029 SetChangedFlag (true); 05030 break; 05031 } 05032 } 05033 return 0; 05034 } 05035 05036 /* --------------------------------------------------------------------------- */ 05037 05038 static const char clearsquare_syntax[] = 05039 N_("ClearSquare(ToggleObject|SelectedElements|SelectedPins)"); 05040 05041 static const char clearsquare_help[] = 05042 N_("Clears the square-flag of pins and pads."); 05043 05044 /* %start-doc actions ClearSquare 05045 05046 Note that @code{Pins} means pins and pads. 05047 05048 @pinshapes 05049 05050 %end-doc */ 05051 05052 static int 05053 ActionClearSquare (int argc, char **argv, Coord x, Coord y) 05054 { 05055 char *function = ARG (0); 05056 if (function && *function) 05057 { 05058 switch (GetFunctionID (function)) 05059 { 05060 case F_ToggleObject: 05061 case F_Object: 05062 { 05063 int type; 05064 void *ptr1, *ptr2, *ptr3; 05065 05066 gui->get_coords (_("Select an Object"), &x, &y); 05067 if ((type = 05068 SearchScreen (x, y, CHANGESQUARE_TYPES, 05069 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 05070 if (ClrObjectSquare (type, ptr1, ptr2, ptr3)) 05071 SetChangedFlag (true); 05072 break; 05073 } 05074 05075 case F_SelectedElements: 05076 if (ClrSelectedSquare (ELEMENT_TYPE)) 05077 SetChangedFlag (true); 05078 break; 05079 05080 case F_SelectedPins: 05081 if (ClrSelectedSquare (PIN_TYPE | PAD_TYPE)) 05082 SetChangedFlag (true); 05083 break; 05084 05085 case F_Selected: 05086 case F_SelectedObjects: 05087 if (ClrSelectedSquare (PIN_TYPE | PAD_TYPE)) 05088 SetChangedFlag (true); 05089 break; 05090 } 05091 } 05092 return 0; 05093 } 05094 05095 /* --------------------------------------------------------------------------- */ 05096 05097 static const char changeoctagon_syntax[] = 05098 N_("ChangeOctagon(Object|ToggleObject|SelectedObjects|Selected)\n" 05099 "ChangeOctagon(SelectedElements|SelectedPins|SelectedVias)"); 05100 05101 static const char changeoctagon_help[] = 05102 N_("Changes the octagon-flag of pins and vias."); 05103 05104 /* %start-doc actions ChangeOctagon 05105 05106 @pinshapes 05107 05108 %end-doc */ 05109 05110 static int 05111 ActionChangeOctagon (int argc, char **argv, Coord x, Coord y) 05112 { 05113 char *function = ARG (0); 05114 if (function) 05115 { 05116 switch (GetFunctionID (function)) 05117 { 05118 case F_ToggleObject: 05119 case F_Object: 05120 { 05121 int type; 05122 void *ptr1, *ptr2, *ptr3; 05123 05124 gui->get_coords (_("Select an Object"), &x, &y); 05125 if ((type = 05126 SearchScreen (x, y, CHANGEOCTAGON_TYPES, 05127 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 05128 if (ChangeObjectOctagon (type, ptr1, ptr2, ptr3)) 05129 SetChangedFlag (true); 05130 break; 05131 } 05132 05133 case F_SelectedElements: 05134 if (ChangeSelectedOctagon (ELEMENT_TYPE)) 05135 SetChangedFlag (true); 05136 break; 05137 05138 case F_SelectedPins: 05139 if (ChangeSelectedOctagon (PIN_TYPE)) 05140 SetChangedFlag (true); 05141 break; 05142 05143 case F_SelectedVias: 05144 if (ChangeSelectedOctagon (VIA_TYPE)) 05145 SetChangedFlag (true); 05146 break; 05147 05148 case F_Selected: 05149 case F_SelectedObjects: 05150 if (ChangeSelectedOctagon (PIN_TYPES)) 05151 SetChangedFlag (true); 05152 break; 05153 } 05154 } 05155 return 0; 05156 } 05157 05158 /* --------------------------------------------------------------------------- */ 05159 05160 static const char setoctagon_syntax[] = 05161 N_("SetOctagon(Object|ToggleObject|SelectedElements|Selected)"); 05162 05163 static const char setoctagon_help[] = N_("Sets the octagon-flag of objects."); 05164 05165 /* %start-doc actions SetOctagon 05166 05167 @pinshapes 05168 05169 %end-doc */ 05170 05171 static int 05172 ActionSetOctagon (int argc, char **argv, Coord x, Coord y) 05173 { 05174 char *function = ARG (0); 05175 if (function) 05176 { 05177 switch (GetFunctionID (function)) 05178 { 05179 case F_ToggleObject: 05180 case F_Object: 05181 { 05182 int type; 05183 void *ptr1, *ptr2, *ptr3; 05184 05185 gui->get_coords (_("Select an Object"), &x, &y); 05186 if ((type = 05187 SearchScreen (x, y, CHANGEOCTAGON_TYPES, 05188 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 05189 if (SetObjectOctagon (type, ptr1, ptr2, ptr3)) 05190 SetChangedFlag (true); 05191 break; 05192 } 05193 05194 case F_SelectedElements: 05195 if (SetSelectedOctagon (ELEMENT_TYPE)) 05196 SetChangedFlag (true); 05197 break; 05198 05199 case F_SelectedPins: 05200 if (SetSelectedOctagon (PIN_TYPE)) 05201 SetChangedFlag (true); 05202 break; 05203 05204 case F_SelectedVias: 05205 if (SetSelectedOctagon (VIA_TYPE)) 05206 SetChangedFlag (true); 05207 break; 05208 05209 case F_Selected: 05210 case F_SelectedObjects: 05211 if (SetSelectedOctagon (PIN_TYPES)) 05212 SetChangedFlag (true); 05213 break; 05214 } 05215 } 05216 return 0; 05217 } 05218 05219 /* --------------------------------------------------------------------------- */ 05220 05221 static const char clearoctagon_syntax[] = 05222 N_("ClearOctagon(ToggleObject|Object|SelectedObjects|Selected)\n" 05223 "ClearOctagon(SelectedElements|SelectedPins|SelectedVias)"); 05224 05225 static const char clearoctagon_help[] = 05226 N_("Clears the octagon-flag of pins and vias."); 05227 05228 /* %start-doc actions ClearOctagon 05229 05230 @pinshapes 05231 05232 %end-doc */ 05233 05234 static int 05235 ActionClearOctagon (int argc, char **argv, Coord x, Coord y) 05236 { 05237 char *function = ARG (0); 05238 if (function) 05239 { 05240 switch (GetFunctionID (function)) 05241 { 05242 case F_ToggleObject: 05243 case F_Object: 05244 { 05245 int type; 05246 void *ptr1, *ptr2, *ptr3; 05247 05248 gui->get_coords (_("Select an Object"), &x, &y); 05249 if ((type = 05250 SearchScreen (Crosshair.X, Crosshair.Y, CHANGEOCTAGON_TYPES, 05251 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 05252 if (ClrObjectOctagon (type, ptr1, ptr2, ptr3)) 05253 SetChangedFlag (true); 05254 break; 05255 } 05256 05257 case F_SelectedElements: 05258 if (ClrSelectedOctagon (ELEMENT_TYPE)) 05259 SetChangedFlag (true); 05260 break; 05261 05262 case F_SelectedPins: 05263 if (ClrSelectedOctagon (PIN_TYPE)) 05264 SetChangedFlag (true); 05265 break; 05266 05267 case F_SelectedVias: 05268 if (ClrSelectedOctagon (VIA_TYPE)) 05269 SetChangedFlag (true); 05270 break; 05271 05272 case F_Selected: 05273 case F_SelectedObjects: 05274 if (ClrSelectedOctagon (PIN_TYPES)) 05275 SetChangedFlag (true); 05276 break; 05277 } 05278 } 05279 return 0; 05280 } 05281 05282 /* --------------------------------------------------------------------------- */ 05283 05284 static const char changehold_syntax[] = 05285 N_("ChangeHole(ToggleObject|Object|SelectedVias|Selected)"); 05286 05287 static const char changehold_help[] = N_("Changes the hole flag of objects."); 05288 05289 /* %start-doc actions ChangeHole 05290 05291 The "hole flag" of a via determines whether the via is a 05292 plated-through hole (not set), or an unplated hole (set). 05293 05294 %end-doc */ 05295 05296 static int 05297 ActionChangeHole (int argc, char **argv, Coord x, Coord y) 05298 { 05299 char *function = ARG (0); 05300 if (function) 05301 { 05302 switch (GetFunctionID (function)) 05303 { 05304 case F_ToggleObject: 05305 case F_Object: 05306 { 05307 int type; 05308 void *ptr1, *ptr2, *ptr3; 05309 05310 gui->get_coords (_("Select an Object"), &x, &y); 05311 if ((type = SearchScreen (x, y, VIA_TYPE, 05312 &ptr1, &ptr2, &ptr3)) != NO_TYPE 05313 && ChangeHole ((PinType *) ptr3)) 05314 IncrementUndoSerialNumber (); 05315 break; 05316 } 05317 05318 case F_SelectedVias: 05319 case F_Selected: 05320 if (ChangeSelectedHole ()) 05321 SetChangedFlag (true); 05322 break; 05323 } 05324 } 05325 return 0; 05326 } 05327 05328 /* --------------------------------------------------------------------------- */ 05329 05330 static const char changepaste_syntax[] = 05331 N_("ChangePaste(ToggleObject|Object|SelectedPads|Selected)"); 05332 05333 static const char changepaste_help[] = 05334 N_("Changes the no paste flag of objects."); 05335 05336 /* %start-doc actions ChangePaste 05337 05338 The "no paste flag" of a pad determines whether the solderpaste 05339 stencil will have an opening for the pad (no set) or if there wil be 05340 no solderpaste on the pad (set). This is used for things such as 05341 fiducial pads. 05342 05343 %end-doc */ 05344 05345 static int 05346 ActionChangePaste (int argc, char **argv, Coord x, Coord y) 05347 { 05348 char *function = ARG (0); 05349 if (function) 05350 { 05351 switch (GetFunctionID (function)) 05352 { 05353 case F_ToggleObject: 05354 case F_Object: 05355 { 05356 int type; 05357 void *ptr1, *ptr2, *ptr3; 05358 05359 gui->get_coords (_("Select an Object"), &x, &y); 05360 if ((type = SearchScreen (x, y, PAD_TYPE, 05361 &ptr1, &ptr2, &ptr3)) != NO_TYPE 05362 && ChangePaste ((PadType *) ptr3)) 05363 IncrementUndoSerialNumber (); 05364 break; 05365 } 05366 05367 case F_SelectedPads: 05368 case F_Selected: 05369 if (ChangeSelectedPaste ()) 05370 SetChangedFlag (true); 05371 break; 05372 } 05373 } 05374 return 0; 05375 } 05376 05377 /* --------------------------------------------------------------------------- */ 05378 05379 static const char select_syntax[] = 05380 N_("Select(Object|ToggleObject)\n" 05381 "Select(All|Block|Connection|BuriedVias)\n" 05382 "Select(ElementByName|ObjectByName|PadByName|PinByName)\n" 05383 "Select(ElementByName|ObjectByName|PadByName|PinByName, Name)\n" 05384 "Select(TextByName|ViaByName|NetByName)\n" 05385 "Select(TextByName|ViaByName|NetByName, Name)\n" 05386 "Select(Convert)"); 05387 05388 static const char select_help[] = N_("Toggles or sets the selection."); 05389 05390 /* %start-doc actions Select 05391 05392 @table @code 05393 05394 @item ElementByName 05395 @item ObjectByName 05396 @item PadByName 05397 @item PinByName 05398 @item TextByName 05399 @item ViaByName 05400 @item NetByName 05401 05402 These all rely on having a regular expression parser built into 05403 @code{pcb}. If the name is not specified then the user is prompted 05404 for a pattern, and all objects that match the pattern and are of the 05405 type specified are selected. 05406 05407 @item Object 05408 @item ToggleObject 05409 Selects the object under the cursor. 05410 05411 @item Block 05412 Selects all objects in a rectangle indicated by the cursor. 05413 05414 @item All 05415 Selects all objects on the board. 05416 05417 @item Found 05418 Selects all connections with the ``found'' flag set. 05419 05420 @item Connection 05421 Selects all connections with the ``connected'' flag set. 05422 05423 @item Connection 05424 Selects all blind and buried vias. 05425 05426 @item Convert 05427 Converts the selected objects to an element. This uses the highest 05428 numbered paste buffer. 05429 05430 @end table 05431 05432 %end-doc */ 05433 05434 static int 05435 ActionSelect (int argc, char **argv, Coord x, Coord y) 05436 { 05437 char *function = ARG (0); 05438 if (function) 05439 { 05440 switch (GetFunctionID (function)) 05441 { 05442 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) 05443 int type; 05444 /* select objects by their names */ 05445 case F_ElementByName: 05446 type = ELEMENT_TYPE; 05447 goto commonByName; 05448 case F_ObjectByName: 05449 type = ALL_TYPES; 05450 goto commonByName; 05451 case F_PadByName: 05452 type = PAD_TYPE; 05453 goto commonByName; 05454 case F_PinByName: 05455 type = PIN_TYPE; 05456 goto commonByName; 05457 case F_TextByName: 05458 type = TEXT_TYPE; 05459 goto commonByName; 05460 case F_ViaByName: 05461 type = VIA_TYPE; 05462 goto commonByName; 05463 case F_NetByName: 05464 type = NET_TYPE; 05465 goto commonByName; 05466 05467 commonByName: 05468 { 05469 char *pattern = ARG (1); 05470 05471 if (pattern 05472 || (pattern = 05473 gui->prompt_for (_("Enter pattern:"), "")) != NULL) 05474 { 05475 if (SelectObjectByName (type, pattern, true)) 05476 SetChangedFlag (true); 05477 if (ARG (1) == NULL) 05478 free (pattern); 05479 } 05480 break; 05481 } 05482 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */ 05483 05484 /* select a single object */ 05485 case F_ToggleObject: 05486 case F_Object: 05487 if (SelectObject ()) 05488 SetChangedFlag (true); 05489 break; 05490 05491 /* all objects in block */ 05492 case F_Block: 05493 { 05494 BoxType box; 05495 05496 box.X1 = MIN (Crosshair.AttachedBox.Point1.X, 05497 Crosshair.AttachedBox.Point2.X); 05498 box.Y1 = MIN (Crosshair.AttachedBox.Point1.Y, 05499 Crosshair.AttachedBox.Point2.Y); 05500 box.X2 = MAX (Crosshair.AttachedBox.Point1.X, 05501 Crosshair.AttachedBox.Point2.X); 05502 box.Y2 = MAX (Crosshair.AttachedBox.Point1.Y, 05503 Crosshair.AttachedBox.Point2.Y); 05504 notify_crosshair_change (false); 05505 NotifyBlock (); 05506 if (Crosshair.AttachedBox.State == STATE_THIRD && 05507 SelectBlock (&box, true)) 05508 { 05509 SetChangedFlag (true); 05510 Crosshair.AttachedBox.State = STATE_FIRST; 05511 } 05512 notify_crosshair_change (true); 05513 break; 05514 } 05515 05516 /* select all visible objects */ 05517 case F_All: 05518 { 05519 BoxType box; 05520 05521 box.X1 = -MAX_COORD; 05522 box.Y1 = -MAX_COORD; 05523 box.X2 = MAX_COORD; 05524 box.Y2 = MAX_COORD; 05525 if (SelectBlock (&box, true)) 05526 SetChangedFlag (true); 05527 break; 05528 } 05529 05530 /* all logical connections */ 05531 case F_Found: 05532 if (SelectByFlag (FOUNDFLAG, true)) 05533 { 05534 Draw (); 05535 IncrementUndoSerialNumber (); 05536 SetChangedFlag (true); 05537 } 05538 break; 05539 05540 /* all physical connections */ 05541 case F_Connection: 05542 if (SelectByFlag (CONNECTEDFLAG, true)) 05543 { 05544 Draw (); 05545 IncrementUndoSerialNumber (); 05546 SetChangedFlag (true); 05547 } 05548 break; 05549 05550 case F_BuriedVias: 05551 if (SelectBuriedVias (true)) 05552 { 05553 Draw (); 05554 IncrementUndoSerialNumber (); 05555 SetChangedFlag (true); 05556 } 05557 break; 05558 05559 case F_Convert: 05560 { 05561 Coord x, y; 05562 Note.Buffer = Settings.BufferNumber; 05563 SetBufferNumber (MAX_BUFFER - 1); 05564 ClearBuffer (PASTEBUFFER); 05565 gui->get_coords (_("Select the Element's Mark Location"), &x, &y); 05566 x = GridFit (x, PCB->Grid, PCB->GridOffsetX); 05567 y = GridFit (y, PCB->Grid, PCB->GridOffsetY); 05568 AddSelectedToBuffer (PASTEBUFFER, x, y, true); 05569 SaveUndoSerialNumber (); 05570 RemoveSelected (); 05571 ConvertBufferToElement (PASTEBUFFER); 05572 RestoreUndoSerialNumber (); 05573 CopyPastebufferToLayout (x, y); 05574 SetBufferNumber (Note.Buffer); 05575 } 05576 break; 05577 05578 default: 05579 AFAIL (select); 05580 break; 05581 } 05582 } 05583 return 0; 05584 } 05585 05586 /* FLAG(have_regex,FlagHaveRegex,0) */ 05587 int 05588 FlagHaveRegex (int parm) 05589 { 05590 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) 05591 return 1; 05592 #else 05593 return 0; 05594 #endif 05595 } 05596 05597 /* --------------------------------------------------------------------------- */ 05598 05599 static const char unselect_syntax[] = 05600 N_("Unselect(All|Block|Connection)\n" 05601 "Unselect(ElementByName|ObjectByName|PadByName|PinByName)\n" 05602 "Unselect(ElementByName|ObjectByName|PadByName|PinByName, Name)\n" 05603 "Unselect(TextByName|ViaByName)\n" 05604 "Unselect(TextByName|ViaByName, Name)\n"); 05605 05606 static const char unselect_help[] = 05607 N_("Unselects the object at the pointer location or the specified objects."); 05608 05609 /* %start-doc actions Unselect 05610 05611 @table @code 05612 05613 @item All 05614 Unselect all objects. 05615 05616 @item Block 05617 Unselect all objects in a rectangle given by the cursor. 05618 05619 @item Connection 05620 Unselect all connections with the ``found'' flag set. 05621 05622 @item ElementByName 05623 @item ObjectByName 05624 @item PadByName 05625 @item PinByName 05626 @item TextByName 05627 @item ViaByName 05628 05629 These all rely on having a regular expression parser built into 05630 @code{pcb}. If the name is not specified then the user is prompted 05631 for a pattern, and all objects that match the pattern and are of the 05632 type specified are unselected. 05633 05634 05635 @end table 05636 05637 %end-doc */ 05638 05639 static int 05640 ActionUnselect (int argc, char **argv, Coord x, Coord y) 05641 { 05642 char *function = ARG (0); 05643 if (function) 05644 { 05645 switch (GetFunctionID (function)) 05646 { 05647 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) 05648 int type; 05649 /* select objects by their names */ 05650 case F_ElementByName: 05651 type = ELEMENT_TYPE; 05652 goto commonByName; 05653 case F_ObjectByName: 05654 type = ALL_TYPES; 05655 goto commonByName; 05656 case F_PadByName: 05657 type = PAD_TYPE; 05658 goto commonByName; 05659 case F_PinByName: 05660 type = PIN_TYPE; 05661 goto commonByName; 05662 case F_TextByName: 05663 type = TEXT_TYPE; 05664 goto commonByName; 05665 case F_ViaByName: 05666 type = VIA_TYPE; 05667 goto commonByName; 05668 case F_NetByName: 05669 type = NET_TYPE; 05670 goto commonByName; 05671 05672 commonByName: 05673 { 05674 char *pattern = ARG (1); 05675 05676 if (pattern 05677 || (pattern = 05678 gui->prompt_for (_("Enter pattern:"), "")) != NULL) 05679 { 05680 if (SelectObjectByName (type, pattern, false)) 05681 SetChangedFlag (true); 05682 if (ARG (1) == NULL) 05683 free (pattern); 05684 } 05685 break; 05686 } 05687 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */ 05688 05689 /* all objects in block */ 05690 case F_Block: 05691 { 05692 BoxType box; 05693 05694 box.X1 = MIN (Crosshair.AttachedBox.Point1.X, 05695 Crosshair.AttachedBox.Point2.X); 05696 box.Y1 = MIN (Crosshair.AttachedBox.Point1.Y, 05697 Crosshair.AttachedBox.Point2.Y); 05698 box.X2 = MAX (Crosshair.AttachedBox.Point1.X, 05699 Crosshair.AttachedBox.Point2.X); 05700 box.Y2 = MAX (Crosshair.AttachedBox.Point1.Y, 05701 Crosshair.AttachedBox.Point2.Y); 05702 notify_crosshair_change (false); 05703 NotifyBlock (); 05704 if (Crosshair.AttachedBox.State == STATE_THIRD && 05705 SelectBlock (&box, false)) 05706 { 05707 SetChangedFlag (true); 05708 Crosshair.AttachedBox.State = STATE_FIRST; 05709 } 05710 notify_crosshair_change (true); 05711 break; 05712 } 05713 05714 /* unselect all visible objects */ 05715 case F_All: 05716 { 05717 BoxType box; 05718 05719 box.X1 = -MAX_COORD; 05720 box.Y1 = -MAX_COORD; 05721 box.X2 = MAX_COORD; 05722 box.Y2 = MAX_COORD; 05723 if (SelectBlock (&box, false)) 05724 SetChangedFlag (true); 05725 break; 05726 } 05727 05728 /* all logical connections */ 05729 case F_Found: 05730 if (SelectByFlag (FOUNDFLAG, false)) 05731 { 05732 Draw (); 05733 IncrementUndoSerialNumber (); 05734 SetChangedFlag (true); 05735 } 05736 break; 05737 05738 /* all physical connections */ 05739 case F_Connection: 05740 if (SelectByFlag (CONNECTEDFLAG, false)) 05741 { 05742 Draw (); 05743 IncrementUndoSerialNumber (); 05744 SetChangedFlag (true); 05745 } 05746 break; 05747 05748 default: 05749 AFAIL (unselect); 05750 break; 05751 05752 } 05753 } 05754 return 0; 05755 } 05756 05757 /* --------------------------------------------------------------------------- */ 05758 05759 static const char saveto_syntax[] = 05760 N_("SaveTo(Layout|LayoutAs,filename)\n" 05761 "SaveTo(AllConnections|AllUnusedPins|ElementConnections,filename)\n" 05762 "SaveTo(PasteBuffer,filename)"); 05763 05764 static const char saveto_help[] = N_("Saves data to a file."); 05765 05766 /* %start-doc actions SaveTo 05767 05768 @table @code 05769 05770 @item Layout 05771 Saves the current layout. 05772 05773 @item LayoutAs 05774 Saves the current layout, and remembers the filename used. 05775 05776 @item AllConnections 05777 Save all connections to a file. 05778 05779 @item AllUnusedPins 05780 List all unused pins to a file. 05781 05782 @item ElementConnections 05783 Save connections to the element at the cursor to a file. 05784 05785 @item PasteBuffer 05786 Save the content of the active Buffer to a file. This is the graphical way to create a footprint. 05787 05788 @end table 05789 05790 %end-doc */ 05791 05792 static int 05793 ActionSaveTo (int argc, char **argv, Coord x, Coord y) 05794 { 05795 char *function; 05796 char *name; 05797 05798 function = ARG (0); 05799 05800 if ( ! function || strcasecmp (function, "Layout") == 0) 05801 { 05802 if (SavePCB (PCB->Filename) == 0) 05803 SetChangedFlag (false); 05804 return 0; 05805 } 05806 05807 if (argc != 2) 05808 AFAIL (saveto); 05809 05810 name = argv[1]; 05811 05812 if (strcasecmp (function, "LayoutAs") == 0) 05813 { 05814 if (SavePCB (name) == 0) 05815 { 05816 SetChangedFlag (false); 05817 free (PCB->Filename); 05818 PCB->Filename = strdup (name); 05819 if (gui->notify_filename_changed != NULL) 05820 gui->notify_filename_changed (); 05821 } 05822 return 0; 05823 } 05824 05825 if (strcasecmp (function, "AllConnections") == 0) 05826 { 05827 FILE *fp; 05828 bool result; 05829 if ((fp = CheckAndOpenFile (name, true, false, &result, NULL)) != NULL) 05830 { 05831 LookupConnectionsToAllElements (fp); 05832 fclose (fp); 05833 SetChangedFlag (true); 05834 } 05835 return 0; 05836 } 05837 05838 if (strcasecmp (function, "AllUnusedPins") == 0) 05839 { 05840 FILE *fp; 05841 bool result; 05842 if ((fp = CheckAndOpenFile (name, true, false, &result, NULL)) != NULL) 05843 { 05844 LookupUnusedPins (fp); 05845 fclose (fp); 05846 SetChangedFlag (true); 05847 } 05848 return 0; 05849 } 05850 05851 if (strcasecmp (function, "ElementConnections") == 0) 05852 { 05853 ElementType *element; 05854 void *ptrtmp; 05855 FILE *fp; 05856 bool result; 05857 05858 if ((SearchScreen (Crosshair.X, Crosshair.Y, ELEMENT_TYPE, 05859 &ptrtmp, &ptrtmp, &ptrtmp)) != NO_TYPE) 05860 { 05861 element = (ElementType *) ptrtmp; 05862 if ((fp = 05863 CheckAndOpenFile (name, true, false, &result, NULL)) != NULL) 05864 { 05865 LookupElementConnections (element, fp); 05866 fclose (fp); 05867 SetChangedFlag (true); 05868 } 05869 } 05870 return 0; 05871 } 05872 05873 if (strcasecmp (function, "PasteBuffer") == 0) 05874 { 05875 return SaveBufferElements (name); 05876 } 05877 05878 AFAIL (saveto); 05879 } 05880 05881 /* --------------------------------------------------------------------------- */ 05882 05883 static const char savesettings_syntax[] = 05884 N_("SaveSettings()\n" 05885 "SaveSettings(local)"); 05886 05887 static const char savesettings_help[] = N_("Saves settings."); 05888 05889 /* %start-doc actions SaveSettings 05890 05891 If you pass no arguments, the settings are stored in 05892 @code{$HOME/.pcb/settings}. If you pass the word @code{local} they're 05893 saved in @code{./pcb.settings}. 05894 05895 %end-doc */ 05896 05897 static int 05898 ActionSaveSettings (int argc, char **argv, Coord x, Coord y) 05899 { 05900 int locally = argc > 0 ? (strncasecmp (argv[0], "local", 5) == 0) : 0; 05901 hid_save_settings (locally); 05902 return 0; 05903 } 05904 05905 /* --------------------------------------------------------------------------- */ 05906 05907 static const char loadfrom_syntax[] = 05908 N_("LoadFrom(Layout|LayoutToBuffer|ElementToBuffer|Netlist|Revert,filename)"); 05909 05910 static const char loadfrom_help[] = N_("Load layout data from a file."); 05911 05912 /* %start-doc actions LoadFrom 05913 05914 This action assumes you know what the filename is. The various GUIs 05915 should have a similar @code{Load} action where the filename is 05916 optional, and will provide their own file selection mechanism to let 05917 you choose the file name. 05918 05919 @table @code 05920 05921 @item Layout 05922 Loads an entire PCB layout, replacing the current one. 05923 05924 @item LayoutToBuffer 05925 Loads an entire PCB layout to the paste buffer. 05926 05927 @item ElementToBuffer 05928 Loads the given element file into the paste buffer. Element files 05929 contain only a single @code{Element} definition, such as the 05930 ``newlib'' library uses. 05931 05932 @item Netlist 05933 Loads a new netlist, replacing any current netlist. 05934 05935 @item Revert 05936 Re-loads the current layout from its disk file, reverting any changes 05937 you may have made. 05938 05939 @end table 05940 05941 %end-doc */ 05942 05943 static int 05944 ActionLoadFrom (int argc, char **argv, Coord x, Coord y) 05945 { 05946 char *function; 05947 char *name; 05948 05949 if (argc < 2) 05950 AFAIL (loadfrom); 05951 05952 function = argv[0]; 05953 name = argv[1]; 05954 05955 if (strcasecmp (function, "ElementToBuffer") == 0) 05956 { 05957 notify_crosshair_change (false); 05958 if (LoadElementToBuffer (PASTEBUFFER, name, true)) 05959 SetMode (PASTEBUFFER_MODE); 05960 notify_crosshair_change (true); 05961 } 05962 05963 else if (strcasecmp (function, "LayoutToBuffer") == 0) 05964 { 05965 notify_crosshair_change (false); 05966 if (LoadLayoutToBuffer (PASTEBUFFER, name)) 05967 SetMode (PASTEBUFFER_MODE); 05968 notify_crosshair_change (true); 05969 } 05970 05971 else if (strcasecmp (function, "Layout") == 0) 05972 { 05973 if (!PCB->Changed || 05974 gui->confirm_dialog (_("OK to override layout data?"), 0)) 05975 LoadPCB (name); 05976 } 05977 05978 else if (strcasecmp (function, "Netlist") == 0) 05979 { 05980 if (PCB->Netlistname) 05981 free (PCB->Netlistname); 05982 PCB->Netlistname = StripWhiteSpaceAndDup (name); 05983 FreeLibraryMemory (&PCB->NetlistLib); 05984 ImportNetlist (PCB->Netlistname); 05985 NetlistChanged (1); 05986 } 05987 else if (strcasecmp (function, "Revert") == 0 && PCB->Filename 05988 && (!PCB->Changed 05989 || gui->confirm_dialog (_("OK to override changes?"), 0))) 05990 { 05991 RevertPCB (); 05992 } 05993 05994 return 0; 05995 } 05996 05997 /* --------------------------------------------------------------------------- */ 05998 05999 static const char new_syntax[] = N_("New([name])"); 06000 06001 static const char new_help[] = N_("Starts a new layout."); 06002 06003 /* %start-doc actions New 06004 06005 If a name is not given, one is prompted for. 06006 06007 %end-doc */ 06008 06009 static int 06010 ActionNew (int argc, char **argv, Coord x, Coord y) 06011 { 06012 char *name = ARG (0); 06013 06014 if (!PCB->Changed || gui->confirm_dialog (_("OK to clear layout data?"), 0)) 06015 { 06016 if (name) 06017 name = strdup (name); 06018 else 06019 name = gui->prompt_for (_("Enter the layout name:"), ""); 06020 06021 if (!name) 06022 return 1; 06023 06024 notify_crosshair_change (false); 06025 /* do emergency saving 06026 * clear the old struct and allocate memory for the new one 06027 */ 06028 if (PCB->Changed && Settings.SaveInTMP) 06029 SaveInTMP (); 06030 RemovePCB (PCB); 06031 PCB = NULL; 06032 PCB = CreateNewPCB (); 06033 CreateNewPCBPost (PCB, 1); 06034 06035 /* setup the new name and reset some values to default */ 06036 free (PCB->Name); 06037 PCB->Name = name; 06038 06039 ResetStackAndVisibility (); 06040 CenterDisplay (PCB->MaxWidth / 2, PCB->MaxHeight / 2, false); 06041 Redraw (); 06042 06043 hid_action ("PCBChanged"); 06044 notify_crosshair_change (true); 06045 return 0; 06046 } 06047 return 1; 06048 } 06049 06054 void 06055 ActionBell (char *volume) 06056 { 06057 gui->beep (); 06058 } 06059 06060 /* --------------------------------------------------------------------------- */ 06061 06062 static const char pastebuffer_syntax[] = 06063 N_("PasteBuffer(AddSelected|Clear|1..MAX_BUFFER)\n" 06064 "PasteBuffer(Rotate, 1..3)\n" 06065 "PasteBuffer(Convert|Save|Restore|Mirror)\n" 06066 "PasteBuffer(ToLayout, X, Y, units)"); 06067 06068 static const char pastebuffer_help[] = 06069 N_("Various operations on the paste buffer."); 06070 06071 /* %start-doc actions PasteBuffer 06072 06073 There are a number of paste buffers; the actual limit is a 06074 compile-time constant @code{MAX_BUFFER} in @file{globalconst.h}. It 06075 is currently @code{5}. One of these is the ``current'' paste buffer, 06076 often referred to as ``the'' paste buffer. 06077 06078 @table @code 06079 06080 @item AddSelected 06081 Copies the selected objects to the current paste buffer. 06082 06083 @item Clear 06084 Remove all objects from the current paste buffer. 06085 06086 @item Convert 06087 Convert the current paste buffer to an element. Vias are converted to 06088 pins, lines are converted to pads. 06089 06090 @item Restore 06091 Convert any elements in the paste buffer back to vias and lines. 06092 06093 @item Mirror 06094 Flip all objects in the paste buffer vertically (up/down flip). To mirror 06095 horizontally, combine this with rotations. 06096 06097 @item Rotate 06098 Rotates the current buffer. The number to pass is 1..3, where 1 means 06099 90 degrees counter clockwise, 2 means 180 degrees, and 3 means 90 06100 degrees clockwise (270 CCW). 06101 06102 @item Save 06103 Saves any elements in the current buffer to the indicated file. 06104 06105 @item ToLayout 06106 Pastes any elements in the current buffer to the indicated X, Y 06107 coordinates in the layout. The @code{X} and @code{Y} are treated like 06108 @code{delta} is for many other objects. For each, if it's prefixed by 06109 @code{+} or @code{-}, then that amount is relative to the last 06110 location. Otherwise, it's absolute. Units can be 06111 @code{mil} or @code{mm}; if unspecified, units are PCB's internal 06112 units, currently 1/100 mil. 06113 06114 06115 @item 1..MAX_BUFFER 06116 Selects the given buffer to be the current paste buffer. 06117 06118 @end table 06119 06120 %end-doc */ 06121 06122 static int 06123 ActionPasteBuffer (int argc, char **argv, Coord x, Coord y) 06124 { 06125 char *function = argc ? argv[0] : (char *)""; 06126 char *sbufnum = argc > 1 ? argv[1] : (char *)""; 06127 char *name; 06128 static char *default_file = NULL; 06129 int free_name = 0; 06130 06131 notify_crosshair_change (false); 06132 if (function) 06133 { 06134 switch (GetFunctionID (function)) 06135 { 06136 /* clear contents of paste buffer */ 06137 case F_Clear: 06138 ClearBuffer (PASTEBUFFER); 06139 break; 06140 06141 /* copies objects to paste buffer */ 06142 case F_AddSelected: 06143 AddSelectedToBuffer (PASTEBUFFER, 0, 0, false); 06144 break; 06145 06146 /* converts buffer contents into an element */ 06147 case F_Convert: 06148 ConvertBufferToElement (PASTEBUFFER); 06149 break; 06150 06151 /* break up element for editing */ 06152 case F_Restore: 06153 SmashBufferElement (PASTEBUFFER); 06154 break; 06155 06156 /* Mirror buffer */ 06157 case F_Mirror: 06158 MirrorBuffer (PASTEBUFFER); 06159 break; 06160 06161 case F_Rotate: 06162 if (sbufnum) 06163 { 06164 RotateBuffer (PASTEBUFFER, (BYTE) atoi (sbufnum)); 06165 crosshair_update_range(); 06166 } 06167 break; 06168 06169 case F_Save: 06170 if (PASTEBUFFER->Data->ElementN == 0) 06171 { 06172 Message (_("Buffer has no elements!\n")); 06173 break; 06174 } 06175 free_name = 0; 06176 if (argc <= 1) 06177 { 06178 name = gui->fileselect (_("Save Paste Buffer As ..."), 06179 _("Choose a file to save the contents of the\n" 06180 "paste buffer to.\n"), 06181 default_file, ".fp", "footprint", 06182 0); 06183 06184 if (default_file) 06185 { 06186 free (default_file); 06187 default_file = NULL; 06188 } 06189 if ( name && *name) 06190 { 06191 default_file = strdup (name); 06192 } 06193 free_name = 1; 06194 } 06195 06196 else 06197 name = argv[1]; 06198 06199 { 06200 FILE *exist; 06201 06202 if ((exist = fopen (name, "r"))) 06203 { 06204 fclose (exist); 06205 if (gui-> 06206 confirm_dialog (_("File exists! Ok to overwrite?"), 0)) 06207 SaveBufferElements (name); 06208 } 06209 else 06210 SaveBufferElements (name); 06211 06212 if (free_name && name) 06213 free (name); 06214 } 06215 break; 06216 06217 case F_ToLayout: 06218 { 06219 static Coord oldx = 0, oldy = 0; 06220 Coord x, y; 06221 bool absolute; 06222 06223 if (argc == 1) 06224 { 06225 x = y = 0; 06226 } 06227 else if (argc == 3 || argc == 4) 06228 { 06229 x = GetValue (ARG (1), ARG (3), &absolute); 06230 if (!absolute) 06231 x += oldx; 06232 y = GetValue (ARG (2), ARG (3), &absolute); 06233 if (!absolute) 06234 y += oldy; 06235 } 06236 else 06237 { 06238 notify_crosshair_change (true); 06239 AFAIL (pastebuffer); 06240 } 06241 06242 oldx = x; 06243 oldy = y; 06244 if (CopyPastebufferToLayout (x, y)) 06245 SetChangedFlag (true); 06246 } 06247 break; 06248 06249 /* set number */ 06250 default: 06251 { 06252 int number = atoi (function); 06253 06254 /* correct number */ 06255 if (number) 06256 SetBufferNumber (number - 1); 06257 } 06258 } 06259 } 06260 06261 notify_crosshair_change (true); 06262 return 0; 06263 } 06264 06265 /* --------------------------------------------------------------------------- */ 06266 06267 static const char undo_syntax[] = N_("Undo()\n" 06268 "Undo(ClearList)"); 06269 06270 static const char undo_help[] = N_("Undo recent changes."); 06271 06272 /* %start-doc actions Undo 06273 06274 The unlimited undo feature of @code{Pcb} allows you to recover from 06275 most operations that materially affect you work. Calling 06276 @code{Undo()} without any parameter recovers from the last (non-undo) 06277 operation. @code{ClearList} is used to release the allocated 06278 memory. @code{ClearList} is called whenever a new layout is started or 06279 loaded. See also @code{Redo} and @code{Atomic}. 06280 06281 Note that undo groups operations by serial number; changes with the 06282 same serial number will be undone (or redone) as a group. See 06283 @code{Atomic}. 06284 06285 %end-doc */ 06286 06287 static int 06288 ActionUndo (int argc, char **argv, Coord x, Coord y) 06289 { 06290 char *function = ARG (0); 06291 if (!function || !*function) 06292 { 06293 /* don't allow undo in the middle of an operation */ 06294 if (Settings.Mode != POLYGONHOLE_MODE && 06295 Crosshair.AttachedObject.State != STATE_FIRST) 06296 return 1; 06297 if (Crosshair.AttachedBox.State != STATE_FIRST 06298 && Settings.Mode != ARC_MODE) 06299 return 1; 06300 /* undo the last operation */ 06301 06302 notify_crosshair_change (false); 06303 if ((Settings.Mode == POLYGON_MODE || 06304 Settings.Mode == POLYGONHOLE_MODE) && 06305 Crosshair.AttachedPolygon.PointN) 06306 { 06307 GoToPreviousPoint (); 06308 notify_crosshair_change (true); 06309 return 0; 06310 } 06311 /* move anchor point if undoing during line creation */ 06312 if (Settings.Mode == LINE_MODE) 06313 { 06314 if (Crosshair.AttachedLine.State == STATE_SECOND) 06315 { 06316 if (TEST_FLAG (AUTODRCFLAG, PCB)) 06317 Undo (true); /* undo the connection find */ 06318 Crosshair.AttachedLine.State = STATE_FIRST; 06319 SetLocalRef (0, 0, false); 06320 notify_crosshair_change (true); 06321 return 0; 06322 } 06323 if (Crosshair.AttachedLine.State == STATE_THIRD) 06324 { 06325 int type; 06326 void *ptr1, *ptr3, *ptrtmp; 06327 LineType *ptr2; 06328 /* this search is guaranteed to succeed */ 06329 SearchObjectByLocation (LINE_TYPE | RATLINE_TYPE, &ptr1, 06330 &ptrtmp, &ptr3, 06331 Crosshair.AttachedLine.Point1.X, 06332 Crosshair.AttachedLine.Point1.Y, 0); 06333 ptr2 = (LineType *) ptrtmp; 06334 06335 /* save both ends of line */ 06336 Crosshair.AttachedLine.Point2.X = ptr2->Point1.X; 06337 Crosshair.AttachedLine.Point2.Y = ptr2->Point1.Y; 06338 if ((type = Undo (true))) 06339 SetChangedFlag (true); 06340 /* check that the undo was of the right type */ 06341 if ((type & UNDO_CREATE) == 0) 06342 { 06343 /* wrong undo type, restore anchor points */ 06344 Crosshair.AttachedLine.Point2.X = 06345 Crosshair.AttachedLine.Point1.X; 06346 Crosshair.AttachedLine.Point2.Y = 06347 Crosshair.AttachedLine.Point1.Y; 06348 notify_crosshair_change (true); 06349 return 0; 06350 } 06351 /* move to new anchor */ 06352 Crosshair.AttachedLine.Point1.X = 06353 Crosshair.AttachedLine.Point2.X; 06354 Crosshair.AttachedLine.Point1.Y = 06355 Crosshair.AttachedLine.Point2.Y; 06356 /* check if an intermediate point was removed */ 06357 if (type & UNDO_REMOVE) 06358 { 06359 /* this search should find the restored line */ 06360 SearchObjectByLocation (LINE_TYPE | RATLINE_TYPE, &ptr1, 06361 &ptrtmp, 06362 &ptr3, 06363 Crosshair.AttachedLine.Point2.X, 06364 Crosshair.AttachedLine.Point2.Y, 0); 06365 ptr2 = (LineType *) ptrtmp; 06366 if (TEST_FLAG (AUTODRCFLAG, PCB)) 06367 { 06368 /* undo loses CONNECTEDFLAG and FOUNDFLAG */ 06369 SET_FLAG(CONNECTEDFLAG, ptr2); 06370 SET_FLAG(FOUNDFLAG, ptr2); 06371 DrawLine (CURRENT, ptr2); 06372 } 06373 Crosshair.AttachedLine.Point1.X = 06374 Crosshair.AttachedLine.Point2.X = ptr2->Point2.X; 06375 Crosshair.AttachedLine.Point1.Y = 06376 Crosshair.AttachedLine.Point2.Y = ptr2->Point2.Y; 06377 } 06378 FitCrosshairIntoGrid (Crosshair.X, Crosshair.Y); 06379 AdjustAttachedObjects (); 06380 if (--addedLines == 0) 06381 { 06382 Crosshair.AttachedLine.State = STATE_SECOND; 06383 lastLayer = CURRENT; 06384 } 06385 else 06386 { 06387 /* this search is guaranteed to succeed too */ 06388 SearchObjectByLocation (LINE_TYPE | RATLINE_TYPE, &ptr1, 06389 &ptrtmp, 06390 &ptr3, 06391 Crosshair.AttachedLine.Point1.X, 06392 Crosshair.AttachedLine.Point1.Y, 0); 06393 ptr2 = (LineType *) ptrtmp; 06394 lastLayer = (LayerType *) ptr1; 06395 } 06396 notify_crosshair_change (true); 06397 return 0; 06398 } 06399 } 06400 if (Settings.Mode == ARC_MODE) 06401 { 06402 if (Crosshair.AttachedBox.State == STATE_SECOND) 06403 { 06404 Crosshair.AttachedBox.State = STATE_FIRST; 06405 notify_crosshair_change (true); 06406 return 0; 06407 } 06408 if (Crosshair.AttachedBox.State == STATE_THIRD) 06409 { 06410 void *ptr1, *ptr2, *ptr3; 06411 BoxType *bx; 06412 /* guaranteed to succeed */ 06413 SearchObjectByLocation (ARC_TYPE, &ptr1, &ptr2, &ptr3, 06414 Crosshair.AttachedBox.Point1.X, 06415 Crosshair.AttachedBox.Point1.Y, 0); 06416 bx = GetArcEnds ((ArcType *) ptr2); 06417 Crosshair.AttachedBox.Point1.X = 06418 Crosshair.AttachedBox.Point2.X = bx->X1; 06419 Crosshair.AttachedBox.Point1.Y = 06420 Crosshair.AttachedBox.Point2.Y = bx->Y1; 06421 AdjustAttachedObjects (); 06422 if (--addedLines == 0) 06423 Crosshair.AttachedBox.State = STATE_SECOND; 06424 } 06425 } 06426 /* undo the last destructive operation */ 06427 if (Undo (true)) 06428 SetChangedFlag (true); 06429 } 06430 else if (function) 06431 { 06432 switch (GetFunctionID (function)) 06433 { 06434 /* clear 'undo objects' list */ 06435 case F_ClearList: 06436 ClearUndoList (false); 06437 break; 06438 } 06439 } 06440 notify_crosshair_change (true); 06441 return 0; 06442 } 06443 06444 /* --------------------------------------------------------------------------- */ 06445 06446 static const char redo_syntax[] = N_("Redo()"); 06447 06448 static const char redo_help[] = N_("Redo recent \"undo\" operations."); 06449 06450 /* %start-doc actions Redo 06451 06452 This routine allows you to recover from the last undo command. You 06453 might want to do this if you thought that undo was going to revert 06454 something other than what it actually did (in case you are confused 06455 about which operations are un-doable), or if you have been backing up 06456 through a long undo list and over-shoot your stopping point. Any 06457 change that is made since the undo in question will trim the redo 06458 list. For example if you add ten lines, then undo three of them you 06459 could use redo to put them back, but if you move a line on the board 06460 before performing the redo, you will lose the ability to "redo" the 06461 three "undone" lines. 06462 06463 %end-doc */ 06464 06465 static int 06466 ActionRedo (int argc, char **argv, Coord x, Coord y) 06467 { 06468 if (((Settings.Mode == POLYGON_MODE || 06469 Settings.Mode == POLYGONHOLE_MODE) && 06470 Crosshair.AttachedPolygon.PointN) || 06471 Crosshair.AttachedLine.State == STATE_SECOND) 06472 return 1; 06473 notify_crosshair_change (false); 06474 if (Redo (true)) 06475 { 06476 SetChangedFlag (true); 06477 if (Settings.Mode == LINE_MODE && 06478 Crosshair.AttachedLine.State != STATE_FIRST) 06479 { 06480 LineType *line = g_list_last (CURRENT->Line)->data; 06481 Crosshair.AttachedLine.Point1.X = 06482 Crosshair.AttachedLine.Point2.X = line->Point2.X; 06483 Crosshair.AttachedLine.Point1.Y = 06484 Crosshair.AttachedLine.Point2.Y = line->Point2.Y; 06485 addedLines++; 06486 } 06487 } 06488 notify_crosshair_change (true); 06489 return 0; 06490 } 06491 06492 /* --------------------------------------------------------------------------- */ 06493 06494 static const char polygon_syntax[] = N_("Polygon(Close|PreviousPoint)"); 06495 06496 static const char polygon_help[] = N_("Some polygon related stuff."); 06497 06498 /* %start-doc actions Polygon 06499 06500 Polygons need a special action routine to make life easier. 06501 06502 @table @code 06503 06504 @item Close 06505 Creates the final segment of the polygon. This may fail if clipping 06506 to 45 degree lines is switched on, in which case a warning is issued. 06507 06508 @item PreviousPoint 06509 Resets the newly entered corner to the previous one. The Undo action 06510 will call Polygon(PreviousPoint) when appropriate to do so. 06511 06512 @end table 06513 06514 %end-doc */ 06515 06516 static int 06517 ActionPolygon (int argc, char **argv, Coord x, Coord y) 06518 { 06519 char *function = ARG (0); 06520 if (function && Settings.Mode == POLYGON_MODE) 06521 { 06522 notify_crosshair_change (false); 06523 switch (GetFunctionID (function)) 06524 { 06525 /* close open polygon if possible */ 06526 case F_Close: 06527 ClosePolygon (); 06528 break; 06529 06530 /* go back to the previous point */ 06531 case F_PreviousPoint: 06532 GoToPreviousPoint (); 06533 break; 06534 } 06535 notify_crosshair_change (true); 06536 } 06537 return 0; 06538 } 06539 06540 /* --------------------------------------------------------------------------- */ 06541 06542 static const char routestyle_syntax[] = N_("RouteStyle(1|2|3|4)"); 06543 06544 static const char routestyle_help[] = 06545 N_("Copies the indicated routing style into the current sizes."); 06546 06547 /* %start-doc actions RouteStyle 06548 06549 %end-doc */ 06550 06551 static int 06552 ActionRouteStyle (int argc, char **argv, Coord x, Coord y) 06553 { 06554 char *str = ARG (0); 06555 RouteStyleType *rts; 06556 int number; 06557 06558 if (str) 06559 { 06560 number = atoi (str); 06561 if (number > 0 && number <= NUM_STYLES) 06562 { 06563 rts = &PCB->RouteStyle[number - 1]; 06564 SetLineSize (rts->Thick); 06565 SetViaSize (rts->Diameter, true); 06566 SetViaDrillingHole (rts->Hole, true); 06567 SetKeepawayWidth (rts->Keepaway); 06568 hid_action("RouteStylesChanged"); 06569 } 06570 } 06571 return 0; 06572 } 06573 06574 06575 /* --------------------------------------------------------------------------- */ 06576 06577 static const char moveobject_syntax[] = N_("MoveObject(X,Y,dim)"); 06578 06579 static const char moveobject_help[] = 06580 N_("Moves the object under the crosshair."); 06581 06582 /* %start-doc actions MoveObject 06583 06584 The @code{X} and @code{Y} are treated like @code{delta} is for many 06585 other objects. For each, if it's prefixed by @code{+} or @code{-}, 06586 then that amount is relative. Otherwise, it's absolute. Units can be 06587 @code{mil} or @code{mm}; if unspecified, units are PCB's internal 06588 units, currently 1/100 mil. 06589 06590 %end-doc */ 06591 06592 static int 06593 ActionMoveObject (int argc, char **argv, Coord x, Coord y) 06594 { 06595 char *x_str = ARG (0); 06596 char *y_str = ARG (1); 06597 char *units = ARG (2); 06598 Coord nx, ny; 06599 bool absolute1, absolute2; 06600 void *ptr1, *ptr2, *ptr3; 06601 int type; 06602 06603 ny = GetValue (y_str, units, &absolute1); 06604 nx = GetValue (x_str, units, &absolute2); 06605 06606 type = SearchScreen (x, y, MOVE_TYPES, &ptr1, &ptr2, &ptr3); 06607 if (type == NO_TYPE) 06608 { 06609 Message (_("Nothing found under crosshair\n")); 06610 return 1; 06611 } 06612 if (absolute1) 06613 nx -= x; 06614 if (absolute2) 06615 ny -= y; 06616 Crosshair.AttachedObject.RubberbandN = 0; 06617 if (TEST_FLAG (RUBBERBANDFLAG, PCB)) 06618 LookupRubberbandLines (type, ptr1, ptr2, ptr3); 06619 if (type == ELEMENT_TYPE) 06620 LookupRatLines (type, ptr1, ptr2, ptr3); 06621 MoveObjectAndRubberband (type, ptr1, ptr2, ptr3, nx, ny); 06622 SetChangedFlag (true); 06623 return 0; 06624 } 06625 06626 /* --------------------------------------------------------------------------- */ 06627 06628 static const char movetocurrentlayer_syntax[] = 06629 N_("MoveToCurrentLayer(Object|SelectedObjects)"); 06630 06631 static const char movetocurrentlayer_help[] = 06632 N_("Moves objects to the current layer."); 06633 06634 /* %start-doc actions MoveToCurrentLayer 06635 06636 Note that moving an element from a component layer to a solder layer, 06637 or from solder to component, won't automatically flip it. Use the 06638 @code{Flip()} action to do that. 06639 06640 %end-doc */ 06641 06642 static int 06643 ActionMoveToCurrentLayer (int argc, char **argv, Coord x, Coord y) 06644 { 06645 char *function = ARG (0); 06646 if (function) 06647 { 06648 switch (GetFunctionID (function)) 06649 { 06650 case F_Object: 06651 { 06652 int type; 06653 void *ptr1, *ptr2, *ptr3; 06654 06655 gui->get_coords (_("Select an Object"), &x, &y); 06656 if ((type = 06657 SearchScreen (x, y, MOVETOLAYER_TYPES, 06658 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 06659 if (MoveObjectToLayer (type, ptr1, ptr2, ptr3, CURRENT, false)) 06660 SetChangedFlag (true); 06661 break; 06662 } 06663 06664 case F_SelectedObjects: 06665 case F_Selected: 06666 if (MoveSelectedObjectsToLayer (CURRENT)) 06667 SetChangedFlag (true); 06668 break; 06669 } 06670 } 06671 return 0; 06672 } 06673 06674 06675 static const char setsame_syntax[] = N_("SetSame()"); 06676 06677 static const char setsame_help[] = 06678 N_("Sets current layer and sizes to match indicated item."); 06679 06680 /* %start-doc actions SetSame 06681 06682 When invoked over any line, arc, polygon, or via, this changes the 06683 current layer to be the layer that item is on, and changes the current 06684 sizes (thickness, keepaway, drill, etc) according to that item. 06685 06686 %end-doc */ 06687 06688 static int 06689 ActionSetSame (int argc, char **argv, Coord x, Coord y) 06690 { 06691 void *ptr1, *ptr2, *ptr3; 06692 int type; 06693 LayerType *layer = CURRENT; 06694 06695 type = SearchScreen (x, y, CLONE_TYPES, &ptr1, &ptr2, &ptr3); 06696 /* set layer current and size from line or arc */ 06697 switch (type) 06698 { 06699 case LINE_TYPE: 06700 notify_crosshair_change (false); 06701 Settings.LineThickness = ((LineType *) ptr2)->Thickness; 06702 Settings.Keepaway = ((LineType *) ptr2)->Clearance / 2; 06703 layer = (LayerType *) ptr1; 06704 if (Settings.Mode != LINE_MODE) 06705 SetMode (LINE_MODE); 06706 notify_crosshair_change (true); 06707 hid_action ("RouteStylesChanged"); 06708 break; 06709 06710 case ARC_TYPE: 06711 notify_crosshair_change (false); 06712 Settings.LineThickness = ((ArcType *) ptr2)->Thickness; 06713 Settings.Keepaway = ((ArcType *) ptr2)->Clearance / 2; 06714 layer = (LayerType *) ptr1; 06715 if (Settings.Mode != ARC_MODE) 06716 SetMode (ARC_MODE); 06717 notify_crosshair_change (true); 06718 hid_action ("RouteStylesChanged"); 06719 break; 06720 06721 case POLYGON_TYPE: 06722 layer = (LayerType *) ptr1; 06723 break; 06724 06725 case VIA_TYPE: 06726 notify_crosshair_change (false); 06727 Settings.ViaThickness = ((PinType *) ptr2)->Thickness; 06728 Settings.ViaDrillingHole = ((PinType *) ptr2)->DrillingHole; 06729 Settings.Keepaway = ((PinType *) ptr2)->Clearance / 2; 06730 if (Settings.Mode != VIA_MODE) 06731 SetMode (VIA_MODE); 06732 notify_crosshair_change (true); 06733 hid_action ("RouteStylesChanged"); 06734 break; 06735 06736 default: 06737 return 1; 06738 } 06739 if (layer != CURRENT) 06740 { 06741 ChangeGroupVisibility (GetLayerNumber (PCB->Data, layer), true, true); 06742 Redraw (); 06743 } 06744 return 0; 06745 } 06746 06747 06748 /* --------------------------------------------------------------------------- */ 06749 06750 static const char setflag_syntax[] = 06751 N_("SetFlag(Object|Selected|SelectedObjects, flag)\n" 06752 "SetFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n" 06753 "SetFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n" 06754 "SetFlag(SelectedElements, flag)\n" 06755 "flag = square | octagon | thermal | join"); 06756 06757 static const char setflag_help[] = N_("Sets flags on objects."); 06758 06759 /* %start-doc actions SetFlag 06760 06761 Turns the given flag on, regardless of its previous setting. See 06762 @code{ChangeFlag}. 06763 06764 @example 06765 SetFlag(SelectedPins,thermal) 06766 @end example 06767 06768 %end-doc */ 06769 06770 static int 06771 ActionSetFlag (int argc, char **argv, Coord x, Coord y) 06772 { 06773 char *function = ARG (0); 06774 char *flag = ARG (1); 06775 ChangeFlag (function, flag, 1, "SetFlag"); 06776 return 0; 06777 } 06778 06779 /* --------------------------------------------------------------------------- */ 06780 06781 static const char clrflag_syntax[] = 06782 N_("ClrFlag(Object|Selected|SelectedObjects, flag)\n" 06783 "ClrFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n" 06784 "ClrFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n" 06785 "ClrFlag(SelectedElements, flag)\n" 06786 "flag = square | octagon | thermal | join"); 06787 06788 static const char clrflag_help[] = N_("Clears flags on objects."); 06789 06790 /* %start-doc actions ClrFlag 06791 06792 Turns the given flag off, regardless of its previous setting. See 06793 @code{ChangeFlag}. 06794 06795 @example 06796 ClrFlag(SelectedLines,join) 06797 @end example 06798 06799 %end-doc */ 06800 06801 static int 06802 ActionClrFlag (int argc, char **argv, Coord x, Coord y) 06803 { 06804 char *function = ARG (0); 06805 char *flag = ARG (1); 06806 ChangeFlag (function, flag, 0, "ClrFlag"); 06807 return 0; 06808 } 06809 06810 /* --------------------------------------------------------------------------- */ 06811 06812 static const char changeflag_syntax[] = 06813 N_("ChangeFlag(Object|Selected|SelectedObjects, flag, value)\n" 06814 "ChangeFlag(SelectedLines|SelectedPins|SelectedVias, flag, value)\n" 06815 "ChangeFlag(SelectedPads|SelectedTexts|SelectedNames, flag, value)\n" 06816 "ChangeFlag(SelectedElements, flag, value)\n" 06817 "flag = square | octagon | thermal | join\n" 06818 "value = 0 | 1"); 06819 06820 static const char changeflag_help[] = N_("Sets or clears flags on objects."); 06821 06822 /* %start-doc actions ChangeFlag 06823 06824 Toggles the given flag on the indicated object(s). The flag may be 06825 one of the flags listed above (square, octagon, thermal, join). The 06826 value may be the number 0 or 1. If the value is 0, the flag is 06827 cleared. If the value is 1, the flag is set. 06828 06829 %end-doc */ 06830 06831 static int 06832 ActionChangeFlag (int argc, char **argv, Coord x, Coord y) 06833 { 06834 char *function = ARG (0); 06835 char *flag = ARG (1); 06836 int value = argc > 2 ? atoi (argv[2]) : -1; 06837 if (value != 0 && value != 1) 06838 AFAIL (changeflag); 06839 06840 ChangeFlag (function, flag, value, "ChangeFlag"); 06841 return 0; 06842 } 06843 06844 06845 static void 06846 ChangeFlag (char *what, char *flag_name, int value, char *cmd_name) 06847 { 06848 bool (*set_object) (int, void *, void *, void *); 06849 bool (*set_selected) (int); 06850 06851 if (NSTRCMP (flag_name, "square") == 0) 06852 { 06853 set_object = value ? SetObjectSquare : ClrObjectSquare; 06854 set_selected = value ? SetSelectedSquare : ClrSelectedSquare; 06855 } 06856 else if (NSTRCMP (flag_name, "octagon") == 0) 06857 { 06858 set_object = value ? SetObjectOctagon : ClrObjectOctagon; 06859 set_selected = value ? SetSelectedOctagon : ClrSelectedOctagon; 06860 } 06861 else if (NSTRCMP (flag_name, "join") == 0) 06862 { 06863 /* Note: these are backwards, because the flag is "clear" but 06864 the command is "join". */ 06865 set_object = value ? ClrObjectJoin : SetObjectJoin; 06866 set_selected = value ? ClrSelectedJoin : SetSelectedJoin; 06867 } 06868 else 06869 { 06870 Message (_("%s(): Flag \"%s\" is not valid\n"), cmd_name, flag_name); 06871 return; 06872 } 06873 06874 switch (GetFunctionID (what)) 06875 { 06876 case F_Object: 06877 { 06878 int type; 06879 void *ptr1, *ptr2, *ptr3; 06880 06881 if ((type = 06882 SearchScreen (Crosshair.X, Crosshair.Y, CHANGESIZE_TYPES, 06883 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 06884 if (TEST_FLAG (LOCKFLAG, (PinType *) ptr2)) 06885 Message (_("Sorry, the object is locked\n")); 06886 if (set_object (type, ptr1, ptr2, ptr3)) 06887 SetChangedFlag (true); 06888 break; 06889 } 06890 06891 case F_SelectedVias: 06892 if (set_selected (VIA_TYPE)) 06893 SetChangedFlag (true); 06894 break; 06895 06896 case F_SelectedPins: 06897 if (set_selected (PIN_TYPE)) 06898 SetChangedFlag (true); 06899 break; 06900 06901 case F_SelectedPads: 06902 if (set_selected (PAD_TYPE)) 06903 SetChangedFlag (true); 06904 break; 06905 06906 case F_SelectedLines: 06907 if (set_selected (LINE_TYPE)) 06908 SetChangedFlag (true); 06909 break; 06910 06911 case F_SelectedTexts: 06912 if (set_selected (TEXT_TYPE)) 06913 SetChangedFlag (true); 06914 break; 06915 06916 case F_SelectedNames: 06917 if (set_selected (ELEMENTNAME_TYPE)) 06918 SetChangedFlag (true); 06919 break; 06920 06921 case F_SelectedElements: 06922 if (set_selected (ELEMENT_TYPE)) 06923 SetChangedFlag (true); 06924 break; 06925 06926 case F_Selected: 06927 case F_SelectedObjects: 06928 if (set_selected (CHANGESIZE_TYPES)) 06929 SetChangedFlag (true); 06930 break; 06931 } 06932 } 06933 06934 /* --------------------------------------------------------------------------- */ 06935 06936 static const char executefile_syntax[] = N_("ExecuteFile(filename)"); 06937 06938 static const char executefile_help[] = N_("Run actions from the given file."); 06939 06940 /* %start-doc actions ExecuteFile 06941 06942 Lines starting with @code{#} are ignored. 06943 06944 %end-doc */ 06945 06946 static int 06947 ActionExecuteFile (int argc, char **argv, Coord x, Coord y) 06948 { 06949 FILE *fp; 06950 char *fname; 06951 char line[256]; 06952 int n = 0; 06953 char *sp; 06954 06955 if (argc != 1) 06956 AFAIL (executefile); 06957 06958 fname = argv[0]; 06959 06960 if ((fp = fopen (fname, "r")) == NULL) 06961 { 06962 fprintf (stderr, _("Could not open actions file \"%s\".\n"), fname); 06963 return 1; 06964 } 06965 06966 defer_updates = 1; 06967 defer_needs_update = 0; 06968 while (fgets (line, sizeof (line), fp) != NULL) 06969 { 06970 n++; 06971 sp = line; 06972 06973 /* eat the trailing newline */ 06974 while (*sp && *sp != '\r' && *sp != '\n') 06975 sp++; 06976 *sp = '\0'; 06977 06978 /* eat leading spaces and tabs */ 06979 sp = line; 06980 while (*sp && (*sp == ' ' || *sp == '\t')) 06981 sp++; 06982 06983 /* 06984 * if we have anything left and its not a comment line 06985 * then execute it 06986 */ 06987 06988 if (*sp && *sp != '#') 06989 { 06990 /*Message ("%s : line %-3d : \"%s\"\n", fname, n, sp);*/ 06991 hid_parse_actions (sp); 06992 } 06993 } 06994 06995 defer_updates = 0; 06996 if (defer_needs_update) 06997 { 06998 IncrementUndoSerialNumber (); 06999 gui->invalidate_all (); 07000 } 07001 fclose (fp); 07002 return 0; 07003 } 07004 07005 /* --------------------------------------------------------------------------- */ 07006 07007 static int 07008 ActionPSCalib (int argc, char **argv, Coord x, Coord y) 07009 { 07010 HID *ps = hid_find_exporter ("ps"); 07011 ps->calibrate (0.0,0.0); 07012 return 0; 07013 } 07014 07015 /* --------------------------------------------------------------------------- */ 07016 07017 static ElementType *element_cache = NULL; 07018 07019 static ElementType * 07020 find_element_by_refdes (char *refdes) 07021 { 07022 if (element_cache 07023 && NAMEONPCB_NAME(element_cache) 07024 && strcmp (NAMEONPCB_NAME(element_cache), refdes) == 0) 07025 return element_cache; 07026 07027 ELEMENT_LOOP (PCB->Data); 07028 { 07029 if (NAMEONPCB_NAME(element) 07030 && strcmp (NAMEONPCB_NAME(element), refdes) == 0) 07031 { 07032 element_cache = element; 07033 return element_cache; 07034 } 07035 } 07036 END_LOOP; 07037 return NULL; 07038 } 07039 07040 static AttributeType * 07041 lookup_attr (AttributeListType *list, const char *name) 07042 { 07043 int i; 07044 for (i=0; i<list->Number; i++) 07045 if (strcmp (list->List[i].name, name) == 0) 07046 return & list->List[i]; 07047 return NULL; 07048 } 07049 07050 static void 07051 delete_attr (AttributeListType *list, AttributeType *attr) 07052 { 07053 int idx = attr - list->List; 07054 if (idx < 0 || idx >= list->Number) 07055 return; 07056 if (list->Number - idx > 1) 07057 memmove (attr, attr+1, (list->Number - idx - 1) * sizeof(AttributeType)); 07058 list->Number --; 07059 } 07060 07061 /* ---------------------------------------------------------------- */ 07062 static const char elementlist_syntax[] = 07063 N_("ElementList(Start|Done|Need,<refdes>,<footprint>,<value>)"); 07064 07065 static const char elementlist_help[] = 07066 N_("Adds the given element if it doesn't already exist."); 07067 07068 /* %start-doc actions elementlist 07069 07070 @table @code 07071 07072 @item Start 07073 Indicates the start of an element list; call this before any Need 07074 actions. 07075 07076 @item Need 07077 Searches the board for an element with a matching refdes. 07078 07079 If found, the value and footprint are updated. 07080 07081 If not found, a new element is created with the given footprint and value. 07082 07083 @item Done 07084 Compares the list of elements needed since the most recent 07085 @code{start} with the list of elements actually on the board. Any 07086 elements that weren't listed are selected, so that the user may delete 07087 them. 07088 07089 @end table 07090 07091 %end-doc */ 07092 07093 static int number_of_footprints_not_found; 07094 07095 static int 07096 parse_layout_attribute_units (char *name, int def) 07097 { 07098 const char *as = AttributeGet (PCB, name); 07099 if (!as) 07100 return def; 07101 return GetValue (as, NULL, NULL); 07102 } 07103 07104 static int 07105 ActionElementList (int argc, char **argv, Coord x, Coord y) 07106 { 07107 ElementType *e = NULL; 07108 char *refdes, *value, *footprint, *old; 07109 char *args[3]; 07110 char *function; 07111 07112 if (argc < 1) 07113 AFAIL (elementlist); 07114 07115 function = argv[0]; 07116 07117 #ifdef DEBUG 07118 printf("Entered ActionElementList, executing function %s\n", function); 07119 #endif 07120 07121 if (strcasecmp (function, "start") == 0) 07122 { 07123 ELEMENT_LOOP (PCB->Data); 07124 { 07125 CLEAR_FLAG (FOUNDFLAG, element); 07126 } 07127 END_LOOP; 07128 element_cache = NULL; 07129 number_of_footprints_not_found = 0; 07130 return 0; 07131 } 07132 07133 if (strcasecmp (function, "done") == 0) 07134 { 07135 ELEMENT_LOOP (PCB->Data); 07136 { 07137 if (TEST_FLAG (FOUNDFLAG, element)) 07138 { 07139 CLEAR_FLAG (FOUNDFLAG, element); 07140 } 07141 else if (! EMPTY_STRING_P (NAMEONPCB_NAME (element))) 07142 { 07143 /* Unnamed elements should remain untouched */ 07144 SET_FLAG (SELECTEDFLAG, element); 07145 } 07146 } 07147 END_LOOP; 07148 if (number_of_footprints_not_found > 0) 07149 gui->confirm_dialog (_("Not all requested footprints were found.\n" 07150 "See the message log for details"), 07151 "Ok", NULL); 07152 return 0; 07153 } 07154 07155 if (strcasecmp (function, "need") != 0) 07156 AFAIL (elementlist); 07157 07158 if (argc != 4) 07159 AFAIL (elementlist); 07160 07161 argc --; 07162 argv ++; 07163 07164 refdes = ARG(0); 07165 footprint = ARG(1); 07166 value = ARG(2); 07167 07168 args[0] = footprint; 07169 args[1] = refdes; 07170 args[2] = value; 07171 07172 #ifdef DEBUG 07173 printf(" ... footprint = %s\n", footprint); 07174 printf(" ... refdes = %s\n", refdes); 07175 printf(" ... value = %s\n", value); 07176 #endif 07177 07178 e = find_element_by_refdes (refdes); 07179 07180 if (!e) 07181 { 07182 Coord nx, ny, d; 07183 07184 #ifdef DEBUG 07185 printf(" ... Footprint not on board, need to add it.\n"); 07186 #endif 07187 /* Not on board, need to add it. */ 07188 if (LoadFootprint(argc, args, x, y)) 07189 { 07190 number_of_footprints_not_found ++; 07191 return 1; 07192 } 07193 07194 nx = PCB->MaxWidth / 2; 07195 ny = PCB->MaxHeight / 2; 07196 d = MIN (PCB->MaxWidth, PCB->MaxHeight) / 10; 07197 07198 nx = parse_layout_attribute_units ("import::newX", nx); 07199 ny = parse_layout_attribute_units ("import::newY", ny); 07200 d = parse_layout_attribute_units ("import::disperse", d); 07201 07202 if (d > 0) 07203 { 07204 nx += rand () % (d*2) - d; 07205 ny += rand () % (d*2) - d; 07206 } 07207 07208 if (nx < 0) 07209 nx = 0; 07210 if (nx >= PCB->MaxWidth) 07211 nx = PCB->MaxWidth - 1; 07212 if (ny < 0) 07213 ny = 0; 07214 if (ny >= PCB->MaxHeight) 07215 ny = PCB->MaxHeight - 1; 07216 07217 /* Place components onto center of board. */ 07218 if (CopyPastebufferToLayout (nx, ny)) 07219 SetChangedFlag (true); 07220 } 07221 07222 else if (e && DESCRIPTION_NAME(e) && strcmp (DESCRIPTION_NAME(e), footprint) != 0) 07223 { 07224 int er, pr, i; 07225 Coord mx, my; 07226 ElementType *pe; 07227 07228 #ifdef DEBUG 07229 printf(" ... Footprint on board, but different from footprint loaded.\n"); 07230 #endif 07231 /* Different footprint, we need to swap them out. */ 07232 if (LoadFootprint(argc, args, x, y)) 07233 { 07234 number_of_footprints_not_found ++; 07235 return 1; 07236 } 07237 07238 er = ElementOrientation (e); 07239 pe = PASTEBUFFER->Data->Element->data; 07240 if (!FRONT (e)) 07241 MirrorElementCoordinates (PASTEBUFFER->Data, pe, pe->MarkY*2 - PCB->MaxHeight); 07242 pr = ElementOrientation (pe); 07243 07244 mx = e->MarkX; 07245 my = e->MarkY; 07246 07247 if (er != pr) 07248 RotateElementLowLevel (PASTEBUFFER->Data, pe, pe->MarkX, pe->MarkY, (er-pr+4)%4); 07249 07250 for (i=0; i<MAX_ELEMENTNAMES; i++) 07251 { 07252 pe->Name[i].X = e->Name[i].X - mx + pe->MarkX ; 07253 pe->Name[i].Y = e->Name[i].Y - my + pe->MarkY ; 07254 pe->Name[i].Direction = e->Name[i].Direction; 07255 pe->Name[i].Scale = e->Name[i].Scale; 07256 } 07257 07258 RemoveElement (e); 07259 07260 if (CopyPastebufferToLayout (mx, my)) 07261 SetChangedFlag (true); 07262 } 07263 07264 /* Now reload footprint */ 07265 element_cache = NULL; 07266 e = find_element_by_refdes (refdes); 07267 07268 old = ChangeElementText (PCB, PCB->Data, e, NAMEONPCB_INDEX, strdup (refdes)); 07269 if (old) 07270 free(old); 07271 old = ChangeElementText (PCB, PCB->Data, e, VALUE_INDEX, strdup (value)); 07272 if (old) 07273 free(old); 07274 07275 SET_FLAG (FOUNDFLAG, e); 07276 07277 #ifdef DEBUG 07278 printf(" ... Leaving ActionElementList.\n"); 07279 #endif 07280 07281 return 0; 07282 } 07283 07284 /* ---------------------------------------------------------------- */ 07285 static const char elementsetattr_syntax[] = 07286 N_("ElementSetAttr(refdes,name[,value])"); 07287 07288 static const char elementsetattr_help[] = 07289 N_("Sets or clears an element-specific attribute."); 07290 07291 /* %start-doc actions elementsetattr 07292 07293 If a value is specified, the named attribute is added (if not already 07294 present) or changed (if it is) to the given value. If the value is 07295 not specified, the given attribute is removed if present. 07296 07297 %end-doc */ 07298 07299 static int 07300 ActionElementSetAttr (int argc, char **argv, Coord x, Coord y) 07301 { 07302 ElementType *e = NULL; 07303 char *refdes, *name, *value; 07304 AttributeType *attr; 07305 07306 if (argc < 2) 07307 { 07308 AFAIL (elementsetattr); 07309 } 07310 07311 refdes = argv[0]; 07312 name = argv[1]; 07313 value = ARG(2); 07314 07315 ELEMENT_LOOP (PCB->Data); 07316 { 07317 if (NSTRCMP (refdes, NAMEONPCB_NAME (element)) == 0) 07318 { 07319 e = element; 07320 break; 07321 } 07322 } 07323 END_LOOP; 07324 07325 if (!e) 07326 { 07327 Message(_("Cannot change attribute of %s - element not found\n"), refdes); 07328 return 1; 07329 } 07330 07331 attr = lookup_attr (&e->Attributes, name); 07332 07333 if (attr && value) 07334 { 07335 free (attr->value); 07336 attr->value = strdup (value); 07337 } 07338 if (attr && ! value) 07339 { 07340 delete_attr (& e->Attributes, attr); 07341 } 07342 if (!attr && value) 07343 { 07344 CreateNewAttribute (& e->Attributes, name, value); 07345 } 07346 07347 return 0; 07348 } 07349 07350 /* ---------------------------------------------------------------- */ 07351 static const char execcommand_syntax[] = N_("ExecCommand(command)"); 07352 07353 static const char execcommand_help[] = N_("Runs a command."); 07354 07355 /* %start-doc actions execcommand 07356 07357 Runs the given command, which is a system executable. 07358 07359 %end-doc */ 07360 07361 static int 07362 ActionExecCommand (int argc, char **argv, Coord x, Coord y) 07363 { 07364 char *command; 07365 07366 if (argc < 1) 07367 { 07368 AFAIL (execcommand); 07369 } 07370 07371 command = ARG(0); 07372 07373 if (system (command)) 07374 return 1; 07375 return 0; 07376 } 07377 07378 /* ---------------------------------------------------------------- */ 07379 07380 static int 07381 pcb_spawnvp (char **argv) 07382 { 07383 #ifdef HAVE__SPAWNVP 07384 int result = _spawnvp (_P_WAIT, argv[0], (const char * const *) argv); 07385 if (result == -1) 07386 return 1; 07387 else 07388 return 0; 07389 #else 07390 int pid; 07391 pid = fork (); 07392 if (pid < 0) 07393 { 07394 /* error */ 07395 Message(_("Cannot fork!")); 07396 return 1; 07397 } 07398 else if (pid == 0) 07399 { 07400 /* Child */ 07401 execvp (argv[0], argv); 07402 exit(1); 07403 } 07404 else 07405 { 07406 int rv; 07407 /* Parent */ 07408 wait (&rv); 07409 } 07410 return 0; 07411 #endif 07412 } 07413 07414 /* ---------------------------------------------------------------- */ 07415 07435 static char * 07436 tempfile_name_new (char * name) 07437 { 07438 char *tmpfile = NULL; 07439 #ifdef HAVE_MKDTEMP 07440 char *tmpdir, *mytmpdir; 07441 size_t len; 07442 #endif 07443 07444 assert ( name != NULL ); 07445 07446 #ifdef HAVE_MKDTEMP 07447 #define TEMPLATE "pcb.XXXXXXXX" 07448 07449 07450 tmpdir = getenv ("TMPDIR"); 07451 07452 /* FIXME -- what about win32? */ 07453 if (tmpdir == NULL) { 07454 tmpdir = "/tmp"; 07455 } 07456 07457 mytmpdir = (char *) malloc (sizeof(char) * 07458 (strlen (tmpdir) + 07459 1 + 07460 strlen (TEMPLATE) + 07461 1)); 07462 if (mytmpdir == NULL) { 07463 fprintf (stderr, "%s(): malloc failed()\n", __FUNCTION__); 07464 exit (1); 07465 } 07466 07467 *mytmpdir = '\0'; 07468 (void)strcat (mytmpdir, tmpdir); 07469 (void)strcat (mytmpdir, PCB_DIR_SEPARATOR_S); 07470 (void)strcat (mytmpdir, TEMPLATE); 07471 if (mkdtemp (mytmpdir) == NULL) { 07472 fprintf (stderr, "%s(): mkdtemp (\"%s\") failed\n", __FUNCTION__, mytmpdir); 07473 free (mytmpdir); 07474 return NULL; 07475 } 07476 07477 07478 len = strlen (mytmpdir) + /* the temp directory name */ 07479 1 + /* the directory sep. */ 07480 strlen (name) + /* the file name */ 07481 1 /* the \0 termination */ 07482 ; 07483 07484 tmpfile = (char *) malloc (sizeof (char) * len); 07485 07486 *tmpfile = '\0'; 07487 (void)strcat (tmpfile, mytmpdir); 07488 (void)strcat (tmpfile, PCB_DIR_SEPARATOR_S); 07489 (void)strcat (tmpfile, name); 07490 07491 free (mytmpdir); 07492 #undef TEMPLATE 07493 #else 07494 /* 07495 * tmpnam() uses a static buffer so strdup() the result right away 07496 * in case someone decides to create multiple temp names. 07497 */ 07498 tmpfile = strdup (tmpnam (NULL)); 07499 #ifdef __WIN32__ 07500 { 07501 /* Guile doesn't like \ separators */ 07502 char *c; 07503 for (c = tmpfile; *c; c++) 07504 if (*c == '\\') 07505 *c = '/'; 07506 } 07507 #endif 07508 #endif 07509 07510 return tmpfile; 07511 } 07512 07513 /* ---------------------------------------------------------------- */ 07514 07521 static int 07522 tempfile_unlink (char * name) 07523 { 07524 #ifdef DEBUG 07525 /* SDB says: Want to keep old temp files for examiniation when debugging */ 07526 return 0; 07527 #else /* DEBUG */ 07528 07529 #ifdef HAVE_MKDTEMP 07530 int e, rc2 = 0; 07531 char *dname; 07532 07533 unlink (name); 07534 /* it is possible that the file was never created so it is OK if the 07535 unlink fails */ 07536 07537 /* now figure out the directory name to remove */ 07538 e = strlen (name) - 1; 07539 while (e > 0 && name[e] != PCB_DIR_SEPARATOR_C) {e--;} 07540 07541 dname = strdup (name); 07542 dname[e] = '\0'; 07543 07544 /* 07545 * at this point, e *should* point to the end of the directory part 07546 * but lets make sure. 07547 */ 07548 if (e > 0) { 07549 rc2 = rmdir (dname); 07550 if (rc2 != 0) { 07551 perror (dname); 07552 } 07553 07554 } else { 07555 fprintf (stderr, _("%s(): Unable to determine temp directory name from the temp file\n"), 07556 __FUNCTION__); 07557 fprintf (stderr, "%s(): \"%s\"\n", 07558 __FUNCTION__, name); 07559 rc2 = -1; 07560 } 07561 07562 /* name was allocated with malloc */ 07563 free (dname); 07564 free (name); 07565 07566 /* 07567 * FIXME - should also return -1 if the temp file exists and was not 07568 * removed. 07569 */ 07570 if (rc2 != 0) { 07571 return -1; 07572 } 07573 07574 #else /* HAVE_MKDTEMP */ 07575 int rc = unlink (name); 07576 07577 if (rc != 0) { 07578 fprintf (stderr, _("Failed to unlink \"%s\"\n"), name); 07579 free (name); 07580 return rc; 07581 } 07582 free (name); 07583 07584 #endif /* HAVE_MKDTEMP */ 07585 #endif /* DEBUG */ 07586 07587 return 0; 07588 } 07589 07590 /* ---------------------------------------------------------------- */ 07591 static const char import_syntax[] = 07592 N_("Import()\n" 07593 "Import([gnetlist|make[,source,source,...]])\n" 07594 "Import(setnewpoint[,(mark|center|X,Y)])\n" 07595 "Import(setdisperse,D,units)\n"); 07596 07597 static const char import_help[] = N_("Import schematics."); 07598 07599 /* %start-doc actions Import 07600 07601 Imports element and netlist data from the schematics (or some other 07602 source). The first parameter, which is optional, is the mode. If not 07603 specified, the @code{import::mode} attribute in the PCB is used. 07604 @code{gnetlist} means gnetlist is used to obtain the information from 07605 the schematics. @code{make} invokes @code{make}, assuming the user 07606 has a @code{Makefile} in the current directory. The @code{Makefile} 07607 will be invoked with the following variables set: 07608 07609 @table @code 07610 07611 @item PCB 07612 The name of the .pcb file 07613 07614 @item SRCLIST 07615 A space-separated list of source files 07616 07617 @item OUT 07618 The name of the file in which to put the command script, which may 07619 contain any @pcb{} actions. By default, this is a temporary file 07620 selected by @pcb{}, but if you specify an @code{import::outfile} 07621 attribute, that file name is used instead (and not automatically 07622 deleted afterwards). 07623 07624 @end table 07625 07626 The target specified to be built is the first of these that apply: 07627 07628 @itemize @bullet 07629 07630 @item 07631 The target specified by an @code{import::target} attribute. 07632 07633 @item 07634 The output file specified by an @code{import::outfile} attribute. 07635 07636 @item 07637 If nothing else is specified, the target is @code{pcb_import}. 07638 07639 @end itemize 07640 07641 If you specify an @code{import::makefile} attribute, then "-f <that 07642 file>" will be added to the command line. 07643 07644 If you specify the mode, you may also specify the source files 07645 (schematics). If you do not specify any, the list of schematics is 07646 obtained by reading the @code{import::src@var{N}} attributes (like 07647 @code{import::src0}, @code{import::src1}, etc). 07648 07649 For compatibility with future extensions to the import file format, 07650 the generated file @emph{must not} start with the two characters 07651 @code{#%}. 07652 07653 If a temporary file is needed the @code{TMPDIR} environment variable 07654 is used to select its location. 07655 07656 Note that the programs @code{gnetlist} and @code{make} may be 07657 overridden by the user via the @code{make-program} and @code{gnetlist} 07658 @code{pcb} settings (i.e. in @code{~/.pcb/settings} or on the command 07659 line). 07660 07661 If @pcb{} cannot determine which schematic(s) to import from, the GUI 07662 is called to let user choose (see @code{ImportGUI()}). 07663 07664 Note that Import() doesn't delete anything - after an Import, elements 07665 which shouldn't be on the board are selected and may be removed once 07666 it's determined that the deletion is appropriate. 07667 07668 If @code{Import()} is called with @code{setnewpoint}, then the location 07669 of new components can be specified. This is where parts show up when 07670 they're added to the board. The default is the center of the board. 07671 07672 @table @code 07673 07674 @item Import(setnewpoint) 07675 07676 Prompts the user to click on the board somewhere, uses that point. If 07677 called by a hotkey, uses the current location of the crosshair. 07678 07679 @item Import(setnewpoint,mark) 07680 07681 Uses the location of the mark. If no mark is present, the point is 07682 not changed. 07683 07684 @item Import(setnewpoint,center) 07685 07686 Resets the point to the center of the board. 07687 07688 @item Import(setnewpoint,X,Y,units) 07689 07690 Sets the point to the specific coordinates given. Example: 07691 @code{Import(setnewpoint,50,25,mm)} 07692 07693 @end table 07694 07695 Note that the X and Y locations are stored in attributes named 07696 @code{import::newX} and @code{import::newY} so you could change them 07697 manually if you wished. 07698 07699 Calling @code{Import(setdisperse,D,units)} sets how much the newly 07700 placed elements are dispersed relative to the set point. For example, 07701 @code{Import(setdisperse,10,mm)} will offset each part randomly up to 07702 10mm away from the point. The default dispersion is 1/10th of the 07703 smallest board dimension. Dispersion is saved in the 07704 @code{import::disperse} attribute. 07705 07706 %end-doc */ 07707 07708 static int 07709 ActionImport (int argc, char **argv, Coord x, Coord y) 07710 { 07711 char *mode; 07712 char **sources = NULL; 07713 int nsources = 0; 07714 07715 #ifdef DEBUG 07716 printf("ActionImport: =========== Entering ActionImport ============\n"); 07717 #endif 07718 07719 mode = ARG (0); 07720 07721 if (mode && strcasecmp (mode, "setdisperse") == 0) 07722 { 07723 char *ds, *units; 07724 char buf[50]; 07725 07726 ds = ARG (1); 07727 units = ARG (2); 07728 if (!ds) 07729 { 07730 const char *as = AttributeGet (PCB, "import::disperse"); 07731 ds = gui->prompt_for(_("Enter dispersion:"), as ? as : "0"); 07732 } 07733 if (units) 07734 { 07735 sprintf(buf, "%s%s", ds, units); 07736 AttributePut (PCB, "import::disperse", buf); 07737 } 07738 else 07739 AttributePut (PCB, "import::disperse", ds); 07740 if (ARG (1) == NULL) 07741 free (ds); 07742 return 0; 07743 } 07744 07745 if (mode && strcasecmp (mode, "setnewpoint") == 0) 07746 { 07747 const char *xs, *ys, *units; 07748 Coord x, y; 07749 char buf[50]; 07750 07751 xs = ARG (1); 07752 ys = ARG (2); 07753 units = ARG (3); 07754 07755 if (!xs) 07756 { 07757 gui->get_coords (_("Click on a location"), &x, &y); 07758 } 07759 else if (strcasecmp (xs, "center") == 0) 07760 { 07761 AttributeRemove (PCB, "import::newX"); 07762 AttributeRemove (PCB, "import::newY"); 07763 return 0; 07764 } 07765 else if (strcasecmp (xs, "mark") == 0) 07766 { 07767 if (!Marked.status) 07768 return 0; 07769 07770 x = Marked.X; 07771 y = Marked.Y; 07772 } 07773 else if (ys) 07774 { 07775 x = GetValue (xs, units, NULL); 07776 y = GetValue (ys, units, NULL); 07777 } 07778 else 07779 { 07780 Message (_("Bad syntax for Import(setnewpoint)")); 07781 return 1; 07782 } 07783 07784 pcb_snprintf (buf, sizeof (buf), "%$ms", x); 07785 AttributePut (PCB, "import::newX", buf); 07786 pcb_snprintf (buf, sizeof (buf), "%$ms", y); 07787 AttributePut (PCB, "import::newY", buf); 07788 return 0; 07789 } 07790 07791 if (! mode) 07792 mode = AttributeGet (PCB, "import::mode"); 07793 if (! mode) 07794 mode = "gnetlist"; 07795 07796 if (argc > 1) 07797 { 07798 sources = argv + 1; 07799 nsources = argc - 1; 07800 } 07801 07802 if (! sources) 07803 { 07804 char sname[40]; 07805 char *src; 07806 07807 nsources = -1; 07808 do { 07809 nsources ++; 07810 sprintf(sname, "import::src%d", nsources); 07811 src = AttributeGet (PCB, sname); 07812 } while (src); 07813 07814 if (nsources > 0) 07815 { 07816 sources = (char **) malloc ((nsources + 1) * sizeof (char *)); 07817 nsources = -1; 07818 do { 07819 nsources ++; 07820 sprintf(sname, "import::src%d", nsources); 07821 src = AttributeGet (PCB, sname); 07822 sources[nsources] = src; 07823 } while (src); 07824 } 07825 } 07826 07827 if (! sources) 07828 { 07829 /* Replace .pcb with .sch and hope for the best. */ 07830 char *pcbname = PCB->Filename; 07831 char *schname; 07832 char *dot, *slash, *bslash; 07833 07834 if (!pcbname) 07835 return hid_action("ImportGUI"); 07836 07837 schname = (char *) malloc (strlen(pcbname) + 5); 07838 strcpy (schname, pcbname); 07839 dot = strchr (schname, '.'); 07840 slash = strchr (schname, '/'); 07841 bslash = strchr (schname, '\\'); 07842 if (dot && slash && dot < slash) 07843 dot = NULL; 07844 if (dot && bslash && dot < bslash) 07845 dot = NULL; 07846 if (dot) 07847 *dot = 0; 07848 strcat (schname, ".sch"); 07849 07850 if (access (schname, F_OK)) 07851 { 07852 free (schname); 07853 return hid_action("ImportGUI"); 07854 } 07855 07856 sources = (char **) malloc (2 * sizeof (char *)); 07857 sources[0] = schname; 07858 sources[1] = NULL; 07859 nsources = 1; 07860 } 07861 07862 if (strcasecmp (mode, "gnetlist") == 0) 07863 { 07864 char *tmpfile = tempfile_name_new ("gnetlist_output"); 07865 char **cmd; 07866 int i; 07867 07868 if (tmpfile == NULL) { 07869 Message (_("Could not create temp file")); 07870 return 1; 07871 } 07872 07873 cmd = (char **) malloc ((7 + nsources) * sizeof (char *)); 07874 cmd[0] = Settings.GnetlistProgram; 07875 cmd[1] = "-g"; 07876 cmd[2] = "pcbfwd"; 07877 cmd[3] = "-o"; 07878 cmd[4] = tmpfile; 07879 cmd[5] = "--"; 07880 for (i=0; i<nsources; i++) 07881 cmd[6+i] = sources[i]; 07882 cmd[6+nsources] = NULL; 07883 07884 #ifdef DEBUG 07885 printf("ActionImport: =========== About to run gnetlist ============\n"); 07886 printf("%s %s %s %s %s %s %s ...\n", 07887 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]); 07888 #endif 07889 07890 if (pcb_spawnvp (cmd)) 07891 { 07892 unlink (tmpfile); 07893 return 1; 07894 } 07895 07896 #ifdef DEBUG 07897 printf("ActionImport: =========== About to run ActionExecuteFile, file = %s ============\n", tmpfile); 07898 #endif 07899 07900 cmd[0] = tmpfile; 07901 cmd[1] = NULL; 07902 ActionExecuteFile (1, cmd, 0, 0); 07903 07904 free (cmd); 07905 tempfile_unlink (tmpfile); 07906 } 07907 else if (strcasecmp (mode, "make") == 0) 07908 { 07909 int must_free_tmpfile = 0; 07910 char *tmpfile; 07911 char *cmd[10]; 07912 int i; 07913 char *srclist; 07914 int srclen; 07915 char *user_outfile = NULL; 07916 char *user_makefile = NULL; 07917 char *user_target = NULL; 07918 07919 07920 user_outfile = AttributeGet (PCB, "import::outfile"); 07921 user_makefile = AttributeGet (PCB, "import::makefile"); 07922 user_target = AttributeGet (PCB, "import::target"); 07923 if (user_outfile && !user_target) 07924 user_target = user_outfile; 07925 07926 if (user_outfile) 07927 tmpfile = user_outfile; 07928 else 07929 { 07930 tmpfile = tempfile_name_new ("gnetlist_output"); 07931 if (tmpfile == NULL) { 07932 Message (_("Could not create temp file")); 07933 free (sources); 07934 return 1; 07935 } 07936 must_free_tmpfile = 1; 07937 } 07938 07939 srclen = sizeof("SRCLIST=") + 2; 07940 for (i=0; i<nsources; i++) 07941 srclen += strlen (sources[i]) + 2; 07942 srclist = (char *) malloc (srclen); 07943 strcpy (srclist, "SRCLIST="); 07944 for (i=0; i<nsources; i++) 07945 { 07946 if (i) 07947 strcat (srclist, " "); 07948 strcat (srclist, sources[i]); 07949 } 07950 07951 cmd[0] = Settings.MakeProgram; 07952 cmd[1] = "-s"; 07953 cmd[2] = Concat ("PCB=", PCB->Filename, NULL); 07954 cmd[3] = srclist; 07955 cmd[4] = Concat ("OUT=", tmpfile, NULL); 07956 i = 5; 07957 if (user_makefile) 07958 { 07959 cmd[i++] = "-f"; 07960 cmd[i++] = user_makefile; 07961 } 07962 cmd[i++] = user_target ? user_target : (char *)"pcb_import"; 07963 cmd[i++] = NULL; 07964 07965 if (pcb_spawnvp (cmd)) 07966 { 07967 if (must_free_tmpfile) 07968 unlink (tmpfile); 07969 free (cmd[2]); 07970 free (cmd[3]); 07971 free (cmd[4]); 07972 return 1; 07973 } 07974 07975 cmd[0] = tmpfile; 07976 cmd[1] = NULL; 07977 ActionExecuteFile (1, cmd, 0, 0); 07978 07979 free (cmd[2]); 07980 free (cmd[3]); 07981 free (cmd[4]); 07982 if (must_free_tmpfile) 07983 tempfile_unlink (tmpfile); 07984 } 07985 else 07986 { 07987 Message (_("Unknown import mode: %s\n"), mode); 07988 return 1; 07989 } 07990 07991 DeleteRats (false); 07992 AddAllRats (false, NULL); 07993 07994 #ifdef DEBUG 07995 printf("ActionImport: =========== Leaving ActionImport ============\n"); 07996 #endif 07997 07998 return 0; 07999 } 08000 08001 /* ------------------------------------------------------------ */ 08002 08003 static const char attributes_syntax[] = 08004 N_("Attributes(Layout|Layer|Element)\n" 08005 "Attributes(Layer,layername)"); 08006 08007 static const char attributes_help[] = 08008 N_("Let the user edit the attributes of the layout, current or given\n" 08009 "layer, or selected element."); 08010 08011 /* %start-doc actions Attributes 08012 08013 This just pops up a dialog letting the user edit the attributes of the 08014 pcb, an element, or a layer. 08015 08016 %end-doc */ 08017 08018 08019 static int 08020 ActionAttributes (int argc, char **argv, Coord x, Coord y) 08021 { 08022 char *function = ARG (0); 08023 char *layername = ARG (1); 08024 char *buf; 08025 08026 if (!function) 08027 AFAIL (attributes); 08028 08029 if (!gui->edit_attributes) 08030 { 08031 Message (_("This GUI doesn't support Attribute Editing\n")); 08032 return 1; 08033 } 08034 08035 switch (GetFunctionID (function)) 08036 { 08037 case F_Layout: 08038 { 08039 gui->edit_attributes(_("Layout Attributes"), &(PCB->Attributes)); 08040 return 0; 08041 } 08042 08043 case F_Layer: 08044 { 08045 LayerType *layer = CURRENT; 08046 if (layername) 08047 { 08048 int i; 08049 layer = NULL; 08050 for (i=0; i<max_copper_layer; i++) 08051 if (strcmp (PCB->Data->Layer[i].Name, layername) == 0) 08052 { 08053 layer = & (PCB->Data->Layer[i]); 08054 break; 08055 } 08056 if (layer == NULL) 08057 { 08058 Message (_("No layer named %s\n"), layername); 08059 return 1; 08060 } 08061 } 08062 buf = (char *) malloc (strlen (layer->Name) + 08063 strlen (_("Layer %s Attributes"))); 08064 sprintf (buf, _("Layer %s Attributes"), layer->Name); 08065 gui->edit_attributes(buf, &(layer->Attributes)); 08066 free (buf); 08067 return 0; 08068 } 08069 08070 case F_Element: 08071 { 08072 int n_found = 0; 08073 ElementType *e = NULL; 08074 ELEMENT_LOOP (PCB->Data); 08075 { 08076 if (TEST_FLAG (SELECTEDFLAG, element)) 08077 { 08078 e = element; 08079 n_found ++; 08080 } 08081 } 08082 END_LOOP; 08083 if (n_found > 1) 08084 { 08085 Message (_("Too many elements selected\n")); 08086 return 1; 08087 } 08088 if (n_found == 0) 08089 { 08090 void *ptrtmp; 08091 gui->get_coords (_("Click on an element"), &x, &y); 08092 if ((SearchScreen 08093 (x, y, ELEMENT_TYPE, &ptrtmp, 08094 &ptrtmp, &ptrtmp)) != NO_TYPE) 08095 e = (ElementType *) ptrtmp; 08096 else 08097 { 08098 Message (_("No element found there\n")); 08099 return 1; 08100 } 08101 } 08102 08103 if (NAMEONPCB_NAME(e)) 08104 { 08105 buf = (char *) malloc (strlen (NAMEONPCB_NAME(e)) + 08106 strlen (_("Element %s Attributes"))); 08107 sprintf(buf, _("Element %s Attributes"), NAMEONPCB_NAME(e)); 08108 } 08109 else 08110 { 08111 buf = strdup (_("Unnamed Element Attributes")); 08112 } 08113 gui->edit_attributes(buf, &(e->Attributes)); 08114 free (buf); 08115 break; 08116 } 08117 08118 default: 08119 AFAIL (attributes); 08120 } 08121 08122 return 0; 08123 } 08124 08125 /* --------------------------------------------------------------------------- */ 08126 08127 static const char setvialayers_syntax[] = 08128 N_("SetViaLayers(Object|SelectedVias|Selected[,ThroughHole|TH])\n" 08129 "SetViaLayers(Object|SelectedVias|Selected,from,to)\n" 08130 "SetViaLayers(Object|SelectedVias|Selected,[c|-|from],[c|-|to])" 08131 ); 08132 08133 static const char setvialayers_help[] = 08134 N_("Sets starting and ending layer for burried/blind/standard vias."); 08135 08136 /* %start-doc actions setvialayers 08137 08138 Specifies layers, which are connected by via. 08139 08140 @table @code 08141 08142 @item TH|ThroughHole 08143 The vias will be set as through-hole, connecting all layers 08144 08145 @item from 08146 layer name or layer number of the first layer to be connected by via; "-" stands for unchanged, "c" stands for currently selected layer 08147 08148 @item to 08149 layer name or layer number of the last layer to be connected by via; "-" stands for unchanged, "c" stands for currently selected layer 08150 08151 @end table 08152 08153 If no parameter us used, dialog is displayed (if implemented in the respective GUI HID). 08154 08155 08156 %end-doc */ 08157 08158 static bool 08159 identify_layer (char *layer_name, Cardinal *layer_no) 08160 { 08161 int layer; 08162 08163 if (strcmp (layer_name, "-") == 0) 08164 { 08165 *layer_no = -1; 08166 return true; 08167 } 08168 08169 if (strcmp (layer_name, "c") == 0) 08170 { 08171 if ((unsigned int)INDEXOFCURRENT < max_copper_layer) 08172 { 08173 *layer_no = INDEXOFCURRENT; 08174 return true; 08175 } 08176 } 08177 08178 layer = SearchLayerByName (PCB->Data, layer_name); 08179 if (layer == -1) 08180 { 08181 if (sscanf (layer_name, "%d", &layer) != 1) 08182 layer = -1; 08183 } 08184 08185 if (layer != -1) 08186 *layer_no = layer; 08187 08188 return (layer != -1); 08189 } 08190 08191 static int 08192 ActionSetViaLayers (int argc, char **argv, Coord x, Coord y) 08193 { 08194 char *function = ARG (0); 08195 char *layername_from = ARG (1); 08196 char *layername_to = ARG (2); 08197 Cardinal layer_from ; 08198 Cardinal layer_to = -1; 08199 08200 if (!function) 08201 AFAIL (setvialayers); 08202 08203 if ( /* !gui->edit_attributes &&*/ argc < 2) 08204 { 08205 Message (_("This GUI doesn't support Via Layers editing\n")); 08206 return 1; 08207 } 08208 08209 if (GetFunctionID (layername_from) == F_ThroughHole) 08210 { 08211 layer_from = 0; 08212 layer_to = 0; 08213 } 08214 else 08215 { 08216 if (!identify_layer (layername_from, &layer_from) 08217 || !identify_layer (layername_to, &layer_to)) 08218 { 08219 Message (_("Sorry, wrong layers specified.\n")); 08220 return 1; 08221 } 08222 } 08223 08224 /* ensure that layer_from < layer_to */ 08225 if (layer_from != -1 08226 && layer_to != -1 08227 && layer_from > layer_to) 08228 { 08229 int tmp; 08230 08231 tmp = layer_from; 08232 layer_from = layer_to; 08233 layer_to = tmp; 08234 } 08235 08236 if (layer_to != -1) 08237 layer_to = min (layer_to, max_copper_layer-1); 08238 08239 switch (GetFunctionID (function)) 08240 { 08241 case F_Object: 08242 { 08243 int type; 08244 void *ptr1, *ptr2, *ptr3; 08245 08246 if ((type = 08247 SearchScreen (Crosshair.X, Crosshair.Y, VIA_TYPE, 08248 &ptr1, &ptr2, &ptr3)) != NO_TYPE) 08249 { 08250 if (TEST_FLAG (LOCKFLAG, (PinType *) ptr1)) 08251 Message (_("Sorry, the object is locked\n")); 08252 else 08253 { 08254 if (ChangeObjectViaLayers (ptr1, ptr2, ptr3, layer_from, layer_to)) 08255 { 08256 SetChangedFlag (true); 08257 } 08258 } 08259 } 08260 break; 08261 case F_SelectedVias: 08262 case F_Selected: 08263 if (ChangeSelectedViaLayers (layer_from, layer_to)) 08264 { 08265 SetChangedFlag (true); 08266 } 08267 break; 08268 } 08269 } 08270 08271 return 0; 08272 } 08273 /* --------------------------------------------------------------------------- */ 08274 08275 HID_Action action_action_list[] = { 08276 {"AddRats", 0, ActionAddRats, 08277 addrats_help, addrats_syntax} 08278 , 08279 {"Attributes", 0, ActionAttributes, 08280 attributes_help, attributes_syntax} 08281 , 08282 {"Atomic", 0, ActionAtomic, 08283 atomic_help, atomic_syntax} 08284 , 08285 {"AutoPlaceSelected", 0, ActionAutoPlaceSelected, 08286 autoplace_help, autoplace_syntax} 08287 , 08288 {"AutoRoute", 0, ActionAutoRoute, 08289 autoroute_help, autoroute_syntax} 08290 , 08291 {"ChangeClearSize", 0, ActionChangeClearSize, 08292 changeclearsize_help, changeclearsize_syntax} 08293 , 08294 {"ChangeDrillSize", 0, ActionChange2ndSize, 08295 changedrillsize_help, changedrillsize_syntax} 08296 , 08297 {"ChangeHole", 0, ActionChangeHole, 08298 changehold_help, changehold_syntax} 08299 , 08300 {"ChangeJoin", 0, ActionChangeJoin, 08301 changejoin_help, changejoin_syntax} 08302 , 08303 {"ChangeName", 0, ActionChangeName, 08304 changename_help, changename_syntax} 08305 , 08306 {"ChangePaste", 0, ActionChangePaste, 08307 changepaste_help, changepaste_syntax} 08308 , 08309 {"ChangePinName", 0, ActionChangePinName, 08310 changepinname_help, changepinname_syntax} 08311 , 08312 {"ChangeSize", 0, ActionChangeSize, 08313 changesize_help, changesize_syntax} 08314 , 08315 {"ChangeSquare", 0, ActionChangeSquare, 08316 changesquare_help, changesquare_syntax} 08317 , 08318 {"ChangeOctagon", 0, ActionChangeOctagon, 08319 changeoctagon_help, changeoctagon_syntax} 08320 , 08321 {"ClearSquare", 0, ActionClearSquare, 08322 clearsquare_help, clearsquare_syntax} 08323 , 08324 {"ClearOctagon", 0, ActionClearOctagon, 08325 clearoctagon_help, clearoctagon_syntax} 08326 , 08327 {"Connection", 0, ActionConnection, 08328 connection_help, connection_syntax} 08329 , 08330 {"Delete", 0, ActionDelete, 08331 delete_help, delete_syntax} 08332 , 08333 {"DeleteRats", 0, ActionDeleteRats, 08334 deleterats_help, deleterats_syntax} 08335 , 08336 {"DisperseElements", 0, ActionDisperseElements, 08337 disperseelements_help, disperseelements_syntax} 08338 , 08339 {"Display", 0, ActionDisplay, 08340 display_help, display_syntax} 08341 , 08342 {"DRC", 0, ActionDRCheck, 08343 drc_help, drc_syntax} 08344 , 08345 {"DumpLibrary", 0, ActionDumpLibrary, 08346 dumplibrary_help, dumplibrary_syntax} 08347 , 08348 {"ExecuteFile", 0, ActionExecuteFile, 08349 executefile_help, executefile_syntax} 08350 , 08351 {"Flip", N_("Click on Object or Flip Point"), ActionFlip, 08352 flip_help, flip_syntax} 08353 , 08354 {"LoadFrom", 0, ActionLoadFrom, 08355 loadfrom_help, loadfrom_syntax} 08356 , 08357 {"MarkCrosshair", 0, ActionMarkCrosshair, 08358 markcrosshair_help, markcrosshair_syntax} 08359 , 08360 {"Message", 0, ActionMessage, 08361 message_help, message_syntax} 08362 , 08363 {"MinMaskGap", 0, ActionMinMaskGap, 08364 minmaskgap_help, minmaskgap_syntax} 08365 , 08366 {"MinClearGap", 0, ActionMinClearGap, 08367 mincleargap_help, mincleargap_syntax} 08368 , 08369 {"Mode", 0, ActionMode, 08370 mode_help, mode_syntax} 08371 , 08372 {"MorphPolygon", 0, ActionMorphPolygon, 08373 morphpolygon_help, morphpolygon_syntax} 08374 , 08375 {"PasteBuffer", 0, ActionPasteBuffer, 08376 pastebuffer_help, pastebuffer_syntax} 08377 , 08378 {"Quit", 0, ActionQuit, 08379 quit_help, quit_syntax} 08380 , 08381 {"RemoveSelected", 0, ActionRemoveSelected, 08382 removeselected_help, removeselected_syntax} 08383 , 08384 {"Renumber", 0, ActionRenumber, 08385 renumber_help, renumber_syntax} 08386 , 08387 {"RipUp", 0, ActionRipUp, 08388 ripup_help, ripup_syntax} 08389 , 08390 {"Select", 0, ActionSelect, 08391 select_help, select_syntax} 08392 , 08393 {"Unselect", 0, ActionUnselect, 08394 unselect_help, unselect_syntax} 08395 , 08396 {"SaveSettings", 0, ActionSaveSettings, 08397 savesettings_help, savesettings_syntax} 08398 , 08399 {"SaveTo", 0, ActionSaveTo, 08400 saveto_help, saveto_syntax} 08401 , 08402 {"SetSquare", 0, ActionSetSquare, 08403 setsquare_help, setsquare_syntax} 08404 , 08405 {"SetOctagon", 0, ActionSetOctagon, 08406 setoctagon_help, setoctagon_syntax} 08407 , 08408 {"SetThermal", 0, ActionSetThermal, 08409 setthermal_help, setthermal_syntax} 08410 , 08411 {"SetValue", 0, ActionSetValue, 08412 setvalue_help, setvalue_syntax} 08413 , 08414 {"ToggleHideName", 0, ActionToggleHideName, 08415 togglehidename_help, togglehidename_syntax} 08416 , 08417 {"Undo", 0, ActionUndo, 08418 undo_help, undo_syntax} 08419 , 08420 {"Redo", 0, ActionRedo, 08421 redo_help, redo_syntax} 08422 , 08423 {"SetSame", N_("Select item to use attributes from"), ActionSetSame, 08424 setsame_help, setsame_syntax} 08425 , 08426 {"SetFlag", 0, ActionSetFlag, 08427 setflag_help, setflag_syntax} 08428 , 08429 {"ClrFlag", 0, ActionClrFlag, 08430 clrflag_help, clrflag_syntax} 08431 , 08432 {"ChangeFlag", 0, ActionChangeFlag, 08433 changeflag_help, changeflag_syntax} 08434 , 08435 {"Polygon", 0, ActionPolygon, 08436 polygon_help, polygon_syntax} 08437 , 08438 {"RouteStyle", 0, ActionRouteStyle, 08439 routestyle_help, routestyle_syntax} 08440 , 08441 {"MoveObject", N_("Select an Object"), ActionMoveObject, 08442 moveobject_help, moveobject_syntax} 08443 , 08444 {"MoveToCurrentLayer", 0, ActionMoveToCurrentLayer, 08445 movetocurrentlayer_help, movetocurrentlayer_syntax} 08446 , 08447 {"New", 0, ActionNew, 08448 new_help, new_syntax} 08449 , 08450 {"pscalib", 0, ActionPSCalib} 08451 , 08452 {"ElementList", 0, ActionElementList, 08453 elementlist_help, elementlist_syntax} 08454 , 08455 {"ElementSetAttr", 0, ActionElementSetAttr, 08456 elementsetattr_help, elementsetattr_syntax} 08457 , 08458 {"ExecCommand", 0, ActionExecCommand, 08459 execcommand_help, execcommand_syntax} 08460 , 08461 {"Import", 0, ActionImport, 08462 import_help, import_syntax} 08463 , 08464 {"SetViaLayers", 0, ActionSetViaLayers, 08465 setvialayers_help, setvialayers_syntax} 08466 , 08467 }; 08468 08469 REGISTER_ACTIONS (action_action_list) 08470