Don't merge lines with different clearances
[geda-pcb/pcjc2.git] / src / buffer.c
blobd31142053fb96c3eefb0a105fb7fa9afc41bc9d1
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
27 /* functions used by paste- and move/copy buffer
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
34 #include <stdlib.h>
35 #include <memory.h>
36 #include <math.h>
38 #include "global.h"
40 #include "buffer.h"
41 #include "copy.h"
42 #include "create.h"
43 #include "crosshair.h"
44 #include "data.h"
45 #include "error.h"
46 #include "mymem.h"
47 #include "mirror.h"
48 #include "misc.h"
49 #include "parse_l.h"
50 #include "polygon.h"
51 #include "rats.h"
52 #include "rotate.h"
53 #include "remove.h"
54 #include "rtree.h"
55 #include "search.h"
56 #include "select.h"
57 #include "set.h"
59 #ifdef HAVE_LIBDMALLOC
60 #include <dmalloc.h>
61 #endif
63 /* ---------------------------------------------------------------------------
64 * some local prototypes
66 static void *AddViaToBuffer (PinType *);
67 static void *AddLineToBuffer (LayerType *, LineType *);
68 static void *AddArcToBuffer (LayerType *, ArcType *);
69 static void *AddRatToBuffer (RatType *);
70 static void *AddTextToBuffer (LayerType *, TextType *);
71 static void *AddPolygonToBuffer (LayerType *, PolygonType *);
72 static void *AddElementToBuffer (ElementType *);
73 static void *MoveViaToBuffer (PinType *);
74 static void *MoveLineToBuffer (LayerType *, LineType *);
75 static void *MoveArcToBuffer (LayerType *, ArcType *);
76 static void *MoveRatToBuffer (RatType *);
77 static void *MoveTextToBuffer (LayerType *, TextType *);
78 static void *MovePolygonToBuffer (LayerType *, PolygonType *);
79 static void *MoveElementToBuffer (ElementType *);
80 static void SwapBuffer (BufferType *);
82 #define ARG(n) (argc > (n) ? argv[n] : 0)
84 /* ---------------------------------------------------------------------------
85 * some local identifiers
87 static DataType *Dest, *Source;
89 static ObjectFunctionType AddBufferFunctions = {
90 AddLineToBuffer,
91 AddTextToBuffer,
92 AddPolygonToBuffer,
93 AddViaToBuffer,
94 AddElementToBuffer,
95 NULL,
96 NULL,
97 NULL,
98 NULL,
99 NULL,
100 AddArcToBuffer,
101 AddRatToBuffer
102 }, MoveBufferFunctions =
105 MoveLineToBuffer,
106 MoveTextToBuffer,
107 MovePolygonToBuffer,
108 MoveViaToBuffer,
109 MoveElementToBuffer,
110 NULL, NULL, NULL, NULL, NULL, MoveArcToBuffer, MoveRatToBuffer};
112 static int ExtraFlag = 0;
114 /* ---------------------------------------------------------------------------
115 * copies a via to paste buffer
117 static void *
118 AddViaToBuffer (PinType *Via)
120 return (CreateNewVia (Dest, Via->X, Via->Y, Via->Thickness, Via->Clearance,
121 Via->Mask, Via->DrillingHole, Via->Name,
122 MaskFlags (Via->Flags, FOUNDFLAG | ExtraFlag)));
125 /* ---------------------------------------------------------------------------
126 * copies a rat-line to paste buffer
128 static void *
129 AddRatToBuffer (RatType *Rat)
131 return (CreateNewRat (Dest, Rat->Point1.X, Rat->Point1.Y,
132 Rat->Point2.X, Rat->Point2.Y, Rat->group1,
133 Rat->group2, Rat->Thickness,
134 MaskFlags (Rat->Flags, FOUNDFLAG | ExtraFlag)));
137 /* ---------------------------------------------------------------------------
138 * copies a line to buffer
140 static void *
141 AddLineToBuffer (LayerType *Layer, LineType *Line)
143 LineType *line;
144 LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
146 line = CreateNewLineOnLayer (layer, Line->Point1.X, Line->Point1.Y,
147 Line->Point2.X, Line->Point2.Y,
148 Line->Thickness, Line->Clearance,
149 MaskFlags (Line->Flags,
150 FOUNDFLAG | ExtraFlag));
151 if (line && Line->Number)
152 line->Number = strdup (Line->Number);
153 return (line);
156 /* ---------------------------------------------------------------------------
157 * copies an arc to buffer
159 static void *
160 AddArcToBuffer (LayerType *Layer, ArcType *Arc)
162 LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
164 return (CreateNewArcOnLayer (layer, Arc->X, Arc->Y,
165 Arc->Width, Arc->Height, Arc->StartAngle, Arc->Delta,
166 Arc->Thickness, Arc->Clearance,
167 MaskFlags (Arc->Flags,
168 FOUNDFLAG | ExtraFlag)));
171 /* ---------------------------------------------------------------------------
172 * copies a text to buffer
174 static void *
175 AddTextToBuffer (LayerType *Layer, TextType *Text)
177 LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
179 return (CreateNewText (layer, &PCB->Font, Text->X, Text->Y,
180 Text->Direction, Text->Scale, Text->TextString,
181 MaskFlags (Text->Flags, ExtraFlag)));
184 /* ---------------------------------------------------------------------------
185 * copies a polygon to buffer
187 static void *
188 AddPolygonToBuffer (LayerType *Layer, PolygonType *Polygon)
190 LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
191 PolygonType *polygon;
193 polygon = CreateNewPolygon (layer, Polygon->Flags);
194 CopyPolygonLowLevel (polygon, Polygon);
196 /* Update the polygon r-tree. Unlike similarly named functions for
197 * other objects, CreateNewPolygon does not do this as it creates a
198 * skeleton polygon object, which won't have correct bounds.
200 if (!layer->polygon_tree)
201 layer->polygon_tree = r_create_tree (NULL, 0, 0);
202 r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
204 CLEAR_FLAG (FOUNDFLAG | ExtraFlag, polygon);
205 return (polygon);
208 /* ---------------------------------------------------------------------------
209 * copies a element to buffer
211 static void *
212 AddElementToBuffer (ElementType *Element)
214 ElementType *element;
216 element = GetElementMemory (Dest);
217 CopyElementLowLevel (Dest, element, Element, false, 0, 0);
218 CLEAR_FLAG (ExtraFlag, element);
219 if (ExtraFlag)
221 ELEMENTTEXT_LOOP (element);
223 CLEAR_FLAG (ExtraFlag, text);
225 END_LOOP;
226 PIN_LOOP (element);
228 CLEAR_FLAG (FOUNDFLAG | ExtraFlag, pin);
230 END_LOOP;
231 PAD_LOOP (element);
233 CLEAR_FLAG (FOUNDFLAG | ExtraFlag, pad);
235 END_LOOP;
237 return (element);
240 /* ---------------------------------------------------------------------------
241 * moves a via to paste buffer without allocating memory for the name
243 static void *
244 MoveViaToBuffer (PinType *via)
246 RestoreToPolygon (Source, VIA_TYPE, via, via);
248 r_delete_entry (Source->via_tree, (BoxType *) via);
249 Source->Via = g_list_remove (Source->Via, via);
250 Source->ViaN --;
251 Dest->Via = g_list_append (Dest->Via, via);
252 Dest->ViaN ++;
254 CLEAR_FLAG (WARNFLAG | FOUNDFLAG, via);
256 if (!Dest->via_tree)
257 Dest->via_tree = r_create_tree (NULL, 0, 0);
258 r_insert_entry (Dest->via_tree, (BoxType *)via, 0);
259 ClearFromPolygon (Dest, VIA_TYPE, via, via);
260 return via;
263 /* ---------------------------------------------------------------------------
264 * moves a rat-line to paste buffer
266 static void *
267 MoveRatToBuffer (RatType *rat)
269 r_delete_entry (Source->rat_tree, (BoxType *)rat);
271 Source->Rat = g_list_remove (Source->Rat, rat);
272 Source->RatN --;
273 Dest->Rat = g_list_append (Dest->Rat, rat);
274 Dest->RatN ++;
276 CLEAR_FLAG (FOUNDFLAG, rat);
278 if (!Dest->rat_tree)
279 Dest->rat_tree = r_create_tree (NULL, 0, 0);
280 r_insert_entry (Dest->rat_tree, (BoxType *)rat, 0);
281 return rat;
284 /* ---------------------------------------------------------------------------
285 * moves a line to buffer
287 static void *
288 MoveLineToBuffer (LayerType *layer, LineType *line)
290 LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
292 RestoreToPolygon (Source, LINE_TYPE, layer, line);
293 r_delete_entry (layer->line_tree, (BoxType *)line);
295 layer->Line = g_list_remove (layer->Line, line);
296 layer->LineN --;
297 lay->Line = g_list_append (lay->Line, line);
298 lay->LineN ++;
300 CLEAR_FLAG (FOUNDFLAG, line);
302 if (!lay->line_tree)
303 lay->line_tree = r_create_tree (NULL, 0, 0);
304 r_insert_entry (lay->line_tree, (BoxType *)line, 0);
305 ClearFromPolygon (Dest, LINE_TYPE, lay, line);
306 return (line);
309 /* ---------------------------------------------------------------------------
310 * moves an arc to buffer
312 static void *
313 MoveArcToBuffer (LayerType *layer, ArcType *arc)
315 LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
317 RestoreToPolygon (Source, ARC_TYPE, layer, arc);
318 r_delete_entry (layer->arc_tree, (BoxType *)arc);
320 layer->Arc = g_list_remove (layer->Arc, arc);
321 layer->ArcN --;
322 lay->Arc = g_list_append (lay->Arc, arc);
323 lay->ArcN ++;
325 CLEAR_FLAG (FOUNDFLAG, arc);
327 if (!lay->arc_tree)
328 lay->arc_tree = r_create_tree (NULL, 0, 0);
329 r_insert_entry (lay->arc_tree, (BoxType *)arc, 0);
330 ClearFromPolygon (Dest, ARC_TYPE, lay, arc);
331 return (arc);
334 /* ---------------------------------------------------------------------------
335 * moves a text to buffer without allocating memory for the name
337 static void *
338 MoveTextToBuffer (LayerType *layer, TextType *text)
340 LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
342 r_delete_entry (layer->text_tree, (BoxType *)text);
343 RestoreToPolygon (Source, TEXT_TYPE, layer, text);
345 layer->Text = g_list_remove (layer->Text, text);
346 layer->TextN --;
347 lay->Text = g_list_append (lay->Text, text);
348 lay->TextN ++;
350 if (!lay->text_tree)
351 lay->text_tree = r_create_tree (NULL, 0, 0);
352 r_insert_entry (lay->text_tree, (BoxType *)text, 0);
353 ClearFromPolygon (Dest, TEXT_TYPE, lay, text);
354 return (text);
357 /* ---------------------------------------------------------------------------
358 * moves a polygon to buffer. Doesn't allocate memory for the points
360 static void *
361 MovePolygonToBuffer (LayerType *layer, PolygonType *polygon)
363 LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
365 r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
367 layer->Polygon = g_list_remove (layer->Polygon, polygon);
368 layer->PolygonN --;
369 lay->Polygon = g_list_append (lay->Polygon, polygon);
370 lay->PolygonN ++;
372 CLEAR_FLAG (FOUNDFLAG, polygon);
374 if (!lay->polygon_tree)
375 lay->polygon_tree = r_create_tree (NULL, 0, 0);
376 r_insert_entry (lay->polygon_tree, (BoxType *)polygon, 0);
377 return (polygon);
380 /* ---------------------------------------------------------------------------
381 * moves a element to buffer without allocating memory for pins/names
383 static void *
384 MoveElementToBuffer (ElementType *element)
387 * Delete the element from the source (remove it from trees,
388 * restore to polygons)
390 r_delete_element (Source, element);
392 Source->Element = g_list_remove (Source->Element, element);
393 Source->ElementN --;
394 Dest->Element = g_list_append (Dest->Element, element);
395 Dest->ElementN ++;
397 PIN_LOOP (element);
399 RestoreToPolygon(Source, PIN_TYPE, element, pin);
400 CLEAR_FLAG (WARNFLAG | FOUNDFLAG, pin);
402 END_LOOP;
403 PAD_LOOP (element);
405 RestoreToPolygon(Source, PAD_TYPE, element, pad);
406 CLEAR_FLAG (WARNFLAG | FOUNDFLAG, pad);
408 END_LOOP;
409 SetElementBoundingBox (Dest, element, &PCB->Font);
411 * Now clear the from the polygons in the destination
413 PIN_LOOP (element);
415 ClearFromPolygon (Dest, PIN_TYPE, element, pin);
417 END_LOOP;
418 PAD_LOOP (element);
420 ClearFromPolygon (Dest, PAD_TYPE, element, pad);
422 END_LOOP;
424 return element;
427 /* ---------------------------------------------------------------------------
428 * calculates the bounding box of the buffer
430 void
431 SetBufferBoundingBox (BufferType *Buffer)
433 BoxType *box = GetDataBoundingBox (Buffer->Data);
435 if (box)
436 Buffer->BoundingBox = *box;
439 /* ---------------------------------------------------------------------------
440 * clears the contents of the paste buffer
442 void
443 ClearBuffer (BufferType *Buffer)
445 if (Buffer && Buffer->Data)
447 FreeDataMemory (Buffer->Data);
448 Buffer->Data->pcb = PCB;
452 /* ----------------------------------------------------------------------
453 * copies all selected and visible objects to the paste buffer
454 * returns true if any objects have been removed
456 void
457 AddSelectedToBuffer (BufferType *Buffer, Coord X, Coord Y, bool LeaveSelected)
459 /* switch crosshair off because adding objects to the pastebuffer
460 * may change the 'valid' area for the cursor
462 if (!LeaveSelected)
463 ExtraFlag = SELECTEDFLAG;
464 notify_crosshair_change (false);
465 Source = PCB->Data;
466 Dest = Buffer->Data;
467 SelectedOperation (&AddBufferFunctions, false, ALL_TYPES);
469 /* set origin to passed or current position */
470 if (X || Y)
472 Buffer->X = X;
473 Buffer->Y = Y;
475 else
477 Buffer->X = Crosshair.X;
478 Buffer->Y = Crosshair.Y;
480 notify_crosshair_change (true);
481 ExtraFlag = 0;
484 /* ---------------------------------------------------------------------------
485 * loads element data from file/library into buffer
486 * parse the file with disabled 'PCB mode' (see parser)
487 * returns false on error
488 * if successful, update some other stuff and reposition the pastebuffer
490 bool
491 LoadElementToBuffer (BufferType *Buffer, char *Name, bool FromFile)
493 ElementType *element;
495 ClearBuffer (Buffer);
496 if (FromFile)
498 if (!ParseElementFile (Buffer->Data, Name))
500 if (Settings.ShowSolderSide)
501 SwapBuffer (Buffer);
502 SetBufferBoundingBox (Buffer);
503 if (Buffer->Data->ElementN)
505 element = Buffer->Data->Element->data;
506 Buffer->X = element->MarkX;
507 Buffer->Y = element->MarkY;
509 else
511 Buffer->X = 0;
512 Buffer->Y = 0;
514 return (true);
517 else
519 if (!ParseLibraryEntry (Buffer->Data, Name)
520 && Buffer->Data->ElementN != 0)
522 element = Buffer->Data->Element->data;
524 /* always add elements using top-side coordinates */
525 if (Settings.ShowSolderSide)
526 MirrorElementCoordinates (Buffer->Data, element, 0);
527 SetElementBoundingBox (Buffer->Data, element, &PCB->Font);
529 /* set buffer offset to 'mark' position */
530 Buffer->X = element->MarkX;
531 Buffer->Y = element->MarkY;
532 SetBufferBoundingBox (Buffer);
533 return (true);
536 /* release memory which might have been acquired */
537 ClearBuffer (Buffer);
538 return (false);
542 /*---------------------------------------------------------------------------
543 * Searches for the given element by "footprint" name, and loads it
544 * into the buffer.
547 /* Figuring out which library entry is the one we want is a little
548 tricky. For file-based footprints, it's just a matter of finding
549 the first match in the search list. For m4-based footprints you
550 need to know what magic to pass to the m4 functions. Fortunately,
551 the footprint needed is determined when we build the m4 libraries
552 and stored as a comment in the description, so we can search for
553 that to find the magic we need. We use a hash to store the
554 corresponding footprints and pointers to the library tree so we can
555 quickly find the various bits we need to load a given
556 footprint. */
558 typedef struct {
559 char *footprint;
560 int footprint_allocated;
561 int menu_idx;
562 int entry_idx;
563 } FootprintHashEntry;
565 static FootprintHashEntry *footprint_hash = 0;
566 int footprint_hash_size = 0;
568 void
569 clear_footprint_hash ()
571 int i;
572 if (!footprint_hash)
573 return;
574 for (i=0; i<footprint_hash_size; i++)
575 if (footprint_hash[i].footprint_allocated)
576 free (footprint_hash[i].footprint);
577 free (footprint_hash);
578 footprint_hash = NULL;
579 footprint_hash_size = 0;
582 /* Used to sort footprint pointer entries. Note we include the index
583 numbers so that same-named footprints are sorted by the library
584 search order. */
585 static int
586 footprint_hash_cmp (const void *va, const void *vb)
588 int i;
589 FootprintHashEntry *a = (FootprintHashEntry *)va;
590 FootprintHashEntry *b = (FootprintHashEntry *)vb;
592 i = strcmp (a->footprint, b->footprint);
593 if (i == 0)
594 i = a->menu_idx - b->menu_idx;
595 if (i == 0)
596 i = a->entry_idx - b->entry_idx;
597 return i;
600 void
601 make_footprint_hash ()
603 int i, j;
604 char *fp;
605 int num_entries = 0;
607 clear_footprint_hash ();
609 for (i=0; i<Library.MenuN; i++)
610 for (j=0; j<Library.Menu[i].EntryN; j++)
611 num_entries ++;
612 footprint_hash = (FootprintHashEntry *)malloc (num_entries * sizeof(FootprintHashEntry));
613 num_entries = 0;
615 /* There are two types of library entries. The file-based types
616 have a Template of (char *)-1 and the AllocatedMemory is the full
617 path to the footprint file. The m4 ones have the footprint name
618 in brackets in the description. */
619 for (i=0; i<Library.MenuN; i++)
621 #ifdef DEBUG
622 printf("In make_footprint_hash, looking for footprints in %s\n",
623 Library.Menu[i].directory);
624 #endif
626 for (j=0; j<Library.Menu[i].EntryN; j++)
628 footprint_hash[num_entries].menu_idx = i;
629 footprint_hash[num_entries].entry_idx = j;
630 if (Library.Menu[i].Entry[j].Template == (char *) -1)
631 /* file */
633 #ifdef DEBUG
634 /* printf(" ... Examining file %s\n", Library.Menu[i].Entry[j].AllocatedMemory); */
635 #endif
636 fp = strrchr (Library.Menu[i].Entry[j].AllocatedMemory, '/');
638 if (!fp)
639 fp = strrchr (Library.Menu[i].Entry[j].AllocatedMemory, '\\');
641 if (fp)
642 fp ++;
643 else
644 fp = Library.Menu[i].Entry[j].AllocatedMemory;
646 #ifdef DEBUG
647 /* printf(" ... found file footprint %s\n", fp); */
648 #endif
650 footprint_hash[num_entries].footprint = fp;
651 footprint_hash[num_entries].footprint_allocated = 0;
653 else
654 /* m4 */
656 fp = strrchr (Library.Menu[i].Entry[j].Description, '[');
657 if (fp)
659 footprint_hash[num_entries].footprint = strdup (fp+1);
660 footprint_hash[num_entries].footprint_allocated = 1;
661 fp = strchr (footprint_hash[num_entries].footprint, ']');
662 if (fp)
663 *fp = 0;
665 else
667 fp = Library.Menu[i].Entry[j].Description;
668 footprint_hash[num_entries].footprint = fp;
669 footprint_hash[num_entries].footprint_allocated = 0;
672 num_entries ++;
676 footprint_hash_size = num_entries;
677 qsort (footprint_hash, num_entries, sizeof(footprint_hash[0]), footprint_hash_cmp);
679 #ifdef DEBUG
680 printf(" found footprints: \n");
681 for (i=0; i<num_entries; i++)
682 printf("[%s]\n", footprint_hash[i].footprint);
683 #endif
687 FootprintHashEntry *
688 search_footprint_hash (const char *footprint)
690 int i, min, max, c;
692 /* Standard binary search */
694 min = -1;
695 max = footprint_hash_size;
697 while (max - min > 1)
699 i = (min+max)/2;
700 c = strcmp (footprint, footprint_hash[i].footprint);
701 if (c < 0)
702 max = i;
703 else if (c > 0)
704 min = i;
705 else
707 /* We want to return the first match, not just any match. */
708 while (i > 0
709 && strcmp (footprint, footprint_hash[i-1].footprint) == 0)
710 i--;
711 return & footprint_hash[i];
714 return NULL;
717 /* Returns zero on success, non-zero on error. */
719 LoadFootprintByName (BufferType *Buffer, char *Footprint)
721 int i;
722 FootprintHashEntry *fpe;
723 LibraryMenuType *menu;
724 LibraryEntryType *entry;
725 char *with_fp = NULL;
727 if (!footprint_hash)
728 make_footprint_hash ();
730 fpe = search_footprint_hash (Footprint);
731 if (!fpe)
733 with_fp = Concat (Footprint, ".fp", NULL);
734 fpe = search_footprint_hash (with_fp);
735 if (fpe)
736 Footprint = with_fp;
738 if (!fpe)
740 Message("Unable to load footprint %s\n", Footprint);
741 return 1;
744 menu = & Library.Menu[fpe->menu_idx];
745 entry = & menu->Entry[fpe->entry_idx];
747 if (entry->Template == (char *) -1)
749 i = LoadElementToBuffer (Buffer, entry->AllocatedMemory, true);
750 if (with_fp)
751 free (with_fp);
752 return i ? 0 : 1;
754 else
756 char *args;
758 args = Concat("'", EMPTY (entry->Template), "' '",
759 EMPTY (entry->Value), "' '", EMPTY (entry->Package), "'", NULL);
760 i = LoadElementToBuffer (Buffer, args, false);
762 free (args);
763 if (with_fp)
764 free (with_fp);
765 return i ? 0 : 1;
768 #ifdef DEBUG
770 int j;
771 printf("Library path: %s\n", Settings.LibraryPath);
772 printf("Library tree: %s\n", Settings.LibraryTree);
774 printf("Library:\n");
775 for (i=0; i<Library.MenuN; i++)
777 printf(" [%02d] Name: %s\n", i, Library.Menu[i].Name);
778 printf(" Dir: %s\n", Library.Menu[i].directory);
779 printf(" Sty: %s\n", Library.Menu[i].Style);
780 for (j=0; j<Library.Menu[i].EntryN; j++)
782 printf(" [%02d] E: %s\n", j, Library.Menu[i].Entry[j].ListEntry);
783 if (Library.Menu[i].Entry[j].Template == (char *) -1)
784 printf(" A: %s\n", Library.Menu[i].Entry[j].AllocatedMemory);
785 else
787 printf(" T: %s\n", Library.Menu[i].Entry[j].Template);
788 printf(" P: %s\n", Library.Menu[i].Entry[j].Package);
789 printf(" V: %s\n", Library.Menu[i].Entry[j].Value);
790 printf(" D: %s\n", Library.Menu[i].Entry[j].Description);
792 if (j == 10)
793 break;
797 #endif
801 static const char loadfootprint_syntax[] = "LoadFootprint(filename[,refdes,value])";
803 static const char loadfootprint_help[] = "Loads a single footprint by name.";
805 /* %start-doc actions LoadFootprint
807 Loads a single footprint by name, rather than by reference or through
808 the library. If a refdes and value are specified, those are inserted
809 into the footprint as well. The footprint remains in the paste buffer.
811 %end-doc */
814 LoadFootprint (int argc, char **argv, Coord x, Coord y)
816 char *name = ARG(0);
817 char *refdes = ARG(1);
818 char *value = ARG(2);
819 ElementType *e;
821 if (!name)
822 AFAIL (loadfootprint);
824 if (LoadFootprintByName (PASTEBUFFER, name))
825 return 1;
827 if (PASTEBUFFER->Data->ElementN == 0)
829 Message("Footprint %s contains no elements", name);
830 return 1;
832 if (PASTEBUFFER->Data->ElementN > 1)
834 Message("Footprint %s contains multiple elements", name);
835 return 1;
838 e = PASTEBUFFER->Data->Element->data;
840 if (e->Name[0].TextString)
841 free (e->Name[0].TextString);
842 e->Name[0].TextString = strdup (name);
844 if (e->Name[1].TextString)
845 free (e->Name[1].TextString);
846 e->Name[1].TextString = refdes ? strdup (refdes) : 0;
848 if (e->Name[2].TextString)
849 free (e->Name[2].TextString);
850 e->Name[2].TextString = value ? strdup (value) : 0;
852 return 0;
855 /*---------------------------------------------------------------------------
857 * break buffer element into pieces
859 bool
860 SmashBufferElement (BufferType *Buffer)
862 ElementType *element;
863 Cardinal group;
864 LayerType *clayer, *slayer;
866 if (Buffer->Data->ElementN != 1)
868 Message (_("Error! Buffer doesn't contain a single element\n"));
869 return (false);
872 * At this point the buffer should contain just a single element.
873 * Now we detach the single element from the buffer and then clear the
874 * buffer, ready to receive the smashed elements. As a result of detaching
875 * it the single element is orphaned from the buffer and thus will not be
876 * free()'d by FreeDataMemory (called via ClearBuffer). This leaves it
877 * around for us to smash bits off it. It then becomes our responsibility,
878 * however, to free the single element when we're finished with it.
880 element = Buffer->Data->Element->data;
881 Buffer->Data->Element = NULL;
882 Buffer->Data->ElementN = 0;
883 ClearBuffer (Buffer);
884 ELEMENTLINE_LOOP (element);
886 CreateNewLineOnLayer (&Buffer->Data->SILKLAYER,
887 line->Point1.X, line->Point1.Y,
888 line->Point2.X, line->Point2.Y,
889 line->Thickness, 0, NoFlags ());
890 if (line)
891 line->Number = STRDUP (NAMEONPCB_NAME (element));
893 END_LOOP;
894 ARC_LOOP (element);
896 CreateNewArcOnLayer (&Buffer->Data->SILKLAYER,
897 arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle,
898 arc->Delta, arc->Thickness, 0, NoFlags ());
900 END_LOOP;
901 PIN_LOOP (element);
903 FlagType f = NoFlags ();
904 AddFlags (f, VIAFLAG);
905 if (TEST_FLAG (HOLEFLAG, pin))
906 AddFlags (f, HOLEFLAG);
908 CreateNewVia (Buffer->Data, pin->X, pin->Y,
909 pin->Thickness, pin->Clearance, pin->Mask,
910 pin->DrillingHole, pin->Number, f);
912 END_LOOP;
913 group =
914 GetLayerGroupNumberByNumber (SWAP_IDENT ? solder_silk_layer :
915 component_silk_layer);
916 clayer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
917 group =
918 GetLayerGroupNumberByNumber (SWAP_IDENT ? component_silk_layer :
919 solder_silk_layer);
920 slayer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
921 PAD_LOOP (element);
923 LineType *line;
924 line = CreateNewLineOnLayer (TEST_FLAG (ONSOLDERFLAG, pad) ? slayer : clayer,
925 pad->Point1.X, pad->Point1.Y,
926 pad->Point2.X, pad->Point2.Y,
927 pad->Thickness, pad->Clearance, NoFlags ());
928 if (line)
929 line->Number = STRDUP (pad->Number);
931 END_LOOP;
932 FreeElementMemory (element);
933 g_slice_free (ElementType, element);
934 return (true);
937 /*---------------------------------------------------------------------------
939 * see if a polygon is a rectangle. If so, canonicalize it.
942 static int
943 polygon_is_rectangle (PolygonType *poly)
945 int i, best;
946 PointType temp[4];
947 if (poly->PointN != 4 || poly->HoleIndexN != 0)
948 return 0;
949 best = 0;
950 for (i=1; i<4; i++)
951 if (poly->Points[i].X < poly->Points[best].X
952 || poly->Points[i].Y < poly->Points[best].Y)
953 best = i;
954 for (i=0; i<4; i++)
955 temp[i] = poly->Points[(i+best)%4];
956 if (temp[0].X == temp[1].X)
957 memcpy (poly->Points, temp, sizeof(temp));
958 else
960 /* reverse them */
961 poly->Points[0] = temp[0];
962 poly->Points[1] = temp[3];
963 poly->Points[2] = temp[2];
964 poly->Points[3] = temp[1];
966 if (poly->Points[0].X == poly->Points[1].X
967 && poly->Points[1].Y == poly->Points[2].Y
968 && poly->Points[2].X == poly->Points[3].X
969 && poly->Points[3].Y == poly->Points[0].Y)
970 return 1;
971 return 0;
974 /*---------------------------------------------------------------------------
976 * convert buffer contents into an element
978 bool
979 ConvertBufferToElement (BufferType *Buffer)
981 ElementType *Element;
982 Cardinal group;
983 Cardinal pin_n = 1;
984 bool hasParts = false, crooked = false;
985 int onsolder;
986 bool warned = false;
988 if (Buffer->Data->pcb == 0)
989 Buffer->Data->pcb = PCB;
991 Element = CreateNewElement (PCB->Data, NULL, &PCB->Font, NoFlags (),
992 NULL, NULL, NULL, PASTEBUFFER->X,
993 PASTEBUFFER->Y, 0, 100,
994 MakeFlags (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG),
995 false);
996 if (!Element)
997 return (false);
998 VIA_LOOP (Buffer->Data);
1000 char num[8];
1001 if (via->Mask < via->Thickness)
1002 via->Mask = via->Thickness + 2 * MASKFRAME;
1003 if (via->Name)
1004 CreateNewPin (Element, via->X, via->Y, via->Thickness,
1005 via->Clearance, via->Mask, via->DrillingHole,
1006 NULL, via->Name, MaskFlags (via->Flags,
1007 VIAFLAG | FOUNDFLAG |
1008 SELECTEDFLAG | WARNFLAG));
1009 else
1011 sprintf (num, "%d", pin_n++);
1012 CreateNewPin (Element, via->X, via->Y, via->Thickness,
1013 via->Clearance, via->Mask, via->DrillingHole,
1014 NULL, num, MaskFlags (via->Flags,
1015 VIAFLAG | FOUNDFLAG | SELECTEDFLAG
1016 | WARNFLAG));
1018 hasParts = true;
1020 END_LOOP;
1022 for (onsolder = 0; onsolder < 2; onsolder ++)
1024 int silk_layer;
1025 int onsolderflag;
1027 if ((!onsolder) == (!SWAP_IDENT))
1029 silk_layer = component_silk_layer;
1030 onsolderflag = NOFLAG;
1032 else
1034 silk_layer = solder_silk_layer;
1035 onsolderflag = ONSOLDERFLAG;
1038 #define MAYBE_WARN() \
1039 if (onsolder && !hasParts && !warned) \
1041 warned = true; \
1042 Message \
1043 (_("Warning: All of the pads are on the opposite\n" \
1044 "side from the component - that's probably not what\n" \
1045 "you wanted\n")); \
1048 /* get the component-side SM pads */
1049 group = GetLayerGroupNumberByNumber (silk_layer);
1050 GROUP_LOOP (Buffer->Data, group);
1052 char num[8];
1053 LINE_LOOP (layer);
1055 sprintf (num, "%d", pin_n++);
1056 CreateNewPad (Element, line->Point1.X,
1057 line->Point1.Y, line->Point2.X,
1058 line->Point2.Y, line->Thickness,
1059 line->Clearance,
1060 line->Thickness + line->Clearance, NULL,
1061 line->Number ? line->Number : num,
1062 MakeFlags (onsolderflag));
1063 MAYBE_WARN();
1064 hasParts = true;
1066 END_LOOP;
1067 POLYGON_LOOP (layer);
1069 Coord x1, y1, x2, y2, w, h, t;
1071 if (! polygon_is_rectangle (polygon))
1073 crooked = true;
1074 continue;
1077 w = polygon->Points[2].X - polygon->Points[0].X;
1078 h = polygon->Points[1].Y - polygon->Points[0].Y;
1079 t = (w < h) ? w : h;
1080 x1 = polygon->Points[0].X + t/2;
1081 y1 = polygon->Points[0].Y + t/2;
1082 x2 = x1 + (w-t);
1083 y2 = y1 + (h-t);
1085 sprintf (num, "%d", pin_n++);
1086 CreateNewPad (Element,
1087 x1, y1, x2, y2, t,
1088 2 * Settings.Keepaway,
1089 t + Settings.Keepaway,
1090 NULL, num,
1091 MakeFlags (SQUAREFLAG | onsolderflag));
1092 MAYBE_WARN();
1093 hasParts = true;
1095 END_LOOP;
1097 END_LOOP;
1100 /* now add the silkscreen. NOTE: elements must have pads or pins too */
1101 LINE_LOOP (&Buffer->Data->SILKLAYER);
1103 if (line->Number && !NAMEONPCB_NAME (Element))
1104 NAMEONPCB_NAME (Element) = strdup (line->Number);
1105 CreateNewLineInElement (Element, line->Point1.X,
1106 line->Point1.Y, line->Point2.X,
1107 line->Point2.Y, line->Thickness);
1108 hasParts = true;
1110 END_LOOP;
1111 ARC_LOOP (&Buffer->Data->SILKLAYER);
1113 CreateNewArcInElement (Element, arc->X, arc->Y, arc->Width,
1114 arc->Height, arc->StartAngle, arc->Delta,
1115 arc->Thickness);
1116 hasParts = true;
1118 END_LOOP;
1119 if (!hasParts)
1121 DestroyObject (PCB->Data, ELEMENT_TYPE, Element, Element, Element);
1122 Message (_("There was nothing to convert!\n"
1123 "Elements must have some silk, pads or pins.\n"));
1124 return (false);
1126 if (crooked)
1127 Message (_("There were polygons that can't be made into pins!\n"
1128 "So they were not included in the element\n"));
1129 Element->MarkX = Buffer->X;
1130 Element->MarkY = Buffer->Y;
1131 if (SWAP_IDENT)
1132 SET_FLAG (ONSOLDERFLAG, Element);
1133 SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
1134 ClearBuffer (Buffer);
1135 MoveObjectToBuffer (Buffer->Data, PCB->Data, ELEMENT_TYPE, Element, Element,
1136 Element);
1137 SetBufferBoundingBox (Buffer);
1138 return (true);
1141 /* ---------------------------------------------------------------------------
1142 * load PCB into buffer
1143 * parse the file with enabled 'PCB mode' (see parser)
1144 * if successful, update some other stuff
1146 bool
1147 LoadLayoutToBuffer (BufferType *Buffer, char *Filename)
1149 PCBType *newPCB = CreateNewPCB (false);
1151 /* new data isn't added to the undo list */
1152 if (!ParsePCB (newPCB, Filename))
1154 /* clear data area and replace pointer */
1155 ClearBuffer (Buffer);
1156 free (Buffer->Data);
1157 Buffer->Data = newPCB->Data;
1158 newPCB->Data = NULL;
1159 Buffer->X = newPCB->CursorX;
1160 Buffer->Y = newPCB->CursorY;
1161 RemovePCB (newPCB);
1162 Buffer->Data->pcb = PCB;
1163 return (true);
1166 /* release unused memory */
1167 RemovePCB (newPCB);
1168 Buffer->Data->pcb = PCB;
1169 return (false);
1172 /* ---------------------------------------------------------------------------
1173 * rotates the contents of the pastebuffer
1175 void
1176 RotateBuffer (BufferType *Buffer, BYTE Number)
1178 /* rotate vias */
1179 VIA_LOOP (Buffer->Data);
1181 r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
1182 ROTATE_VIA_LOWLEVEL (via, Buffer->X, Buffer->Y, Number);
1183 SetPinBoundingBox (via);
1184 r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
1186 END_LOOP;
1188 /* elements */
1189 ELEMENT_LOOP (Buffer->Data);
1191 RotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
1192 Number);
1194 END_LOOP;
1196 /* all layer related objects */
1197 ALLLINE_LOOP (Buffer->Data);
1199 r_delete_entry (layer->line_tree, (BoxType *)line);
1200 RotateLineLowLevel (line, Buffer->X, Buffer->Y, Number);
1201 r_insert_entry (layer->line_tree, (BoxType *)line, 0);
1203 ENDALL_LOOP;
1204 ALLARC_LOOP (Buffer->Data);
1206 r_delete_entry (layer->arc_tree, (BoxType *)arc);
1207 RotateArcLowLevel (arc, Buffer->X, Buffer->Y, Number);
1208 r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
1210 ENDALL_LOOP;
1211 ALLTEXT_LOOP (Buffer->Data);
1213 r_delete_entry (layer->text_tree, (BoxType *)text);
1214 RotateTextLowLevel (text, Buffer->X, Buffer->Y, Number);
1215 r_insert_entry (layer->text_tree, (BoxType *)text, 0);
1217 ENDALL_LOOP;
1218 ALLPOLYGON_LOOP (Buffer->Data);
1220 r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
1221 RotatePolygonLowLevel (polygon, Buffer->X, Buffer->Y, Number);
1222 r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
1224 ENDALL_LOOP;
1226 /* finally the origin and the bounding box */
1227 ROTATE (Buffer->X, Buffer->Y, Buffer->X, Buffer->Y, Number);
1228 RotateBoxLowLevel (&Buffer->BoundingBox, Buffer->X, Buffer->Y, Number);
1229 SetCrosshairRangeToBuffer ();
1232 static void
1233 free_rotate (Coord *x, Coord *y, Coord cx, Coord cy, double cosa, double sina)
1235 double nx, ny;
1236 Coord px = *x - cx;
1237 Coord py = *y - cy;
1239 nx = px * cosa + py * sina;
1240 ny = py * cosa - px * sina;
1242 *x = nx + cx;
1243 *y = ny + cy;
1246 void
1247 FreeRotateElementLowLevel (DataType *Data, ElementType *Element,
1248 Coord X, Coord Y,
1249 double cosa, double sina, Angle angle)
1251 /* solder side objects need a different orientation */
1253 /* the text subroutine decides by itself if the direction
1254 * is to be corrected
1256 #if 0
1257 ELEMENTTEXT_LOOP (Element);
1259 if (Data && Data->name_tree[n])
1260 r_delete_entry (Data->name_tree[n], (BoxType *)text);
1261 RotateTextLowLevel (text, X, Y, Number);
1263 END_LOOP;
1264 #endif
1265 ELEMENTLINE_LOOP (Element);
1267 free_rotate (&line->Point1.X, &line->Point1.Y, X, Y, cosa, sina);
1268 free_rotate (&line->Point2.X, &line->Point2.Y, X, Y, cosa, sina);
1269 SetLineBoundingBox (line);
1271 END_LOOP;
1272 PIN_LOOP (Element);
1274 /* pre-delete the pins from the pin-tree before their coordinates change */
1275 if (Data)
1276 r_delete_entry (Data->pin_tree, (BoxType *)pin);
1277 RestoreToPolygon (Data, PIN_TYPE, Element, pin);
1278 free_rotate (&pin->X, &pin->Y, X, Y, cosa, sina);
1279 SetPinBoundingBox (pin);
1281 END_LOOP;
1282 PAD_LOOP (Element);
1284 /* pre-delete the pads before their coordinates change */
1285 if (Data)
1286 r_delete_entry (Data->pad_tree, (BoxType *)pad);
1287 RestoreToPolygon (Data, PAD_TYPE, Element, pad);
1288 free_rotate (&pad->Point1.X, &pad->Point1.Y, X, Y, cosa, sina);
1289 free_rotate (&pad->Point2.X, &pad->Point2.Y, X, Y, cosa, sina);
1290 SetLineBoundingBox ((LineType *) pad);
1292 END_LOOP;
1293 ARC_LOOP (Element);
1295 free_rotate (&arc->X, &arc->Y, X, Y, cosa, sina);
1296 arc->StartAngle = NormalizeAngle (arc->StartAngle + angle);
1298 END_LOOP;
1300 free_rotate (&Element->MarkX, &Element->MarkY, X, Y, cosa, sina);
1301 SetElementBoundingBox (Data, Element, &PCB->Font);
1302 ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element);
1305 void
1306 FreeRotateBuffer (BufferType *Buffer, Angle angle)
1308 double cosa, sina;
1310 cosa = cos(angle * M_PI/180.0);
1311 sina = sin(angle * M_PI/180.0);
1313 /* rotate vias */
1314 VIA_LOOP (Buffer->Data);
1316 r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
1317 free_rotate (&via->X, &via->Y, Buffer->X, Buffer->Y, cosa, sina);
1318 SetPinBoundingBox (via);
1319 r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
1321 END_LOOP;
1323 /* elements */
1324 ELEMENT_LOOP (Buffer->Data);
1326 FreeRotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
1327 cosa, sina, angle);
1329 END_LOOP;
1331 /* all layer related objects */
1332 ALLLINE_LOOP (Buffer->Data);
1334 r_delete_entry (layer->line_tree, (BoxType *)line);
1335 free_rotate (&line->Point1.X, &line->Point1.Y, Buffer->X, Buffer->Y, cosa, sina);
1336 free_rotate (&line->Point2.X, &line->Point2.Y, Buffer->X, Buffer->Y, cosa, sina);
1337 SetLineBoundingBox (line);
1338 r_insert_entry (layer->line_tree, (BoxType *)line, 0);
1340 ENDALL_LOOP;
1341 ALLARC_LOOP (Buffer->Data);
1343 r_delete_entry (layer->arc_tree, (BoxType *)arc);
1344 free_rotate (&arc->X, &arc->Y, Buffer->X, Buffer->Y, cosa, sina);
1345 arc->StartAngle = NormalizeAngle (arc->StartAngle + angle);
1346 r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
1348 ENDALL_LOOP;
1349 /* FIXME: rotate text */
1350 ALLPOLYGON_LOOP (Buffer->Data);
1352 r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
1353 POLYGONPOINT_LOOP (polygon);
1355 free_rotate (&point->X, &point->Y, Buffer->X, Buffer->Y, cosa, sina);
1357 END_LOOP;
1358 SetPolygonBoundingBox (polygon);
1359 r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
1361 ENDALL_LOOP;
1363 SetBufferBoundingBox (Buffer);
1364 SetCrosshairRangeToBuffer ();
1368 /* -------------------------------------------------------------------------- */
1370 static const char freerotatebuffer_syntax[] =
1371 "FreeRotateBuffer([Angle])";
1373 static const char freerotatebuffer_help[] =
1374 "Rotates the current paste buffer contents by the specified angle. The\n"
1375 "angle is given in degrees. If no angle is given, the user is prompted\n"
1376 "for one.\n";
1378 /* %start-doc actions FreeRotateBuffer
1380 Rotates the contents of the pastebuffer by an arbitrary angle. If no
1381 angle is given, the user is prompted for one.
1383 %end-doc */
1386 ActionFreeRotateBuffer(int argc, char **argv, Coord x, Coord y)
1388 char *angle_s;
1390 if (argc < 1)
1391 angle_s = gui->prompt_for ("Enter Rotation (degrees, CCW):", "0");
1392 else
1393 angle_s = argv[0];
1395 notify_crosshair_change (false);
1396 FreeRotateBuffer(PASTEBUFFER, strtod(angle_s, 0));
1397 notify_crosshair_change (true);
1398 return 0;
1401 /* ---------------------------------------------------------------------------
1402 * initializes the buffers by allocating memory
1404 void
1405 InitBuffers (void)
1407 int i;
1409 for (i = 0; i < MAX_BUFFER; i++)
1410 Buffers[i].Data = CreateNewBuffer ();
1413 void
1414 SwapBuffers (void)
1416 int i;
1418 for (i = 0; i < MAX_BUFFER; i++)
1419 SwapBuffer (&Buffers[i]);
1420 SetCrosshairRangeToBuffer ();
1423 void
1424 MirrorBuffer (BufferType *Buffer)
1426 int i;
1428 if (Buffer->Data->ElementN)
1430 Message (_("You can't mirror a buffer that has elements!\n"));
1431 return;
1433 for (i = 0; i < max_copper_layer + 2; i++)
1435 LayerType *layer = Buffer->Data->Layer + i;
1436 if (layer->TextN)
1438 Message (_("You can't mirror a buffer that has text!\n"));
1439 return;
1442 /* set buffer offset to 'mark' position */
1443 Buffer->X = SWAP_X (Buffer->X);
1444 Buffer->Y = SWAP_Y (Buffer->Y);
1445 VIA_LOOP (Buffer->Data);
1447 via->X = SWAP_X (via->X);
1448 via->Y = SWAP_Y (via->Y);
1450 END_LOOP;
1451 ALLLINE_LOOP (Buffer->Data);
1453 line->Point1.X = SWAP_X (line->Point1.X);
1454 line->Point1.Y = SWAP_Y (line->Point1.Y);
1455 line->Point2.X = SWAP_X (line->Point2.X);
1456 line->Point2.Y = SWAP_Y (line->Point2.Y);
1458 ENDALL_LOOP;
1459 ALLARC_LOOP (Buffer->Data);
1461 arc->X = SWAP_X (arc->X);
1462 arc->Y = SWAP_Y (arc->Y);
1463 arc->StartAngle = SWAP_ANGLE (arc->StartAngle);
1464 arc->Delta = SWAP_DELTA (arc->Delta);
1465 SetArcBoundingBox (arc);
1467 ENDALL_LOOP;
1468 ALLPOLYGON_LOOP (Buffer->Data);
1470 POLYGONPOINT_LOOP (polygon);
1472 point->X = SWAP_X (point->X);
1473 point->Y = SWAP_Y (point->Y);
1475 END_LOOP;
1476 SetPolygonBoundingBox (polygon);
1478 ENDALL_LOOP;
1479 SetBufferBoundingBox (Buffer);
1480 SetCrosshairRangeToBuffer ();
1484 /* ---------------------------------------------------------------------------
1485 * flip components/tracks from one side to the other
1487 static void
1488 SwapBuffer (BufferType *Buffer)
1490 int j, k;
1491 Cardinal sgroup, cgroup;
1492 LayerType swap;
1494 ELEMENT_LOOP (Buffer->Data);
1496 r_delete_element (Buffer->Data, element);
1497 MirrorElementCoordinates (Buffer->Data, element, 0);
1499 END_LOOP;
1500 /* set buffer offset to 'mark' position */
1501 Buffer->X = SWAP_X (Buffer->X);
1502 Buffer->Y = SWAP_Y (Buffer->Y);
1503 VIA_LOOP (Buffer->Data);
1505 r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
1506 via->X = SWAP_X (via->X);
1507 via->Y = SWAP_Y (via->Y);
1508 SetPinBoundingBox (via);
1509 r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
1511 END_LOOP;
1512 ALLLINE_LOOP (Buffer->Data);
1514 r_delete_entry (layer->line_tree, (BoxType *)line);
1515 line->Point1.X = SWAP_X (line->Point1.X);
1516 line->Point1.Y = SWAP_Y (line->Point1.Y);
1517 line->Point2.X = SWAP_X (line->Point2.X);
1518 line->Point2.Y = SWAP_Y (line->Point2.Y);
1519 SetLineBoundingBox (line);
1520 r_insert_entry (layer->line_tree, (BoxType *)line, 0);
1522 ENDALL_LOOP;
1523 ALLARC_LOOP (Buffer->Data);
1525 r_delete_entry (layer->arc_tree, (BoxType *)arc);
1526 arc->X = SWAP_X (arc->X);
1527 arc->Y = SWAP_Y (arc->Y);
1528 arc->StartAngle = SWAP_ANGLE (arc->StartAngle);
1529 arc->Delta = SWAP_DELTA (arc->Delta);
1530 SetArcBoundingBox (arc);
1531 r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
1533 ENDALL_LOOP;
1534 ALLPOLYGON_LOOP (Buffer->Data);
1536 r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
1537 POLYGONPOINT_LOOP (polygon);
1539 point->X = SWAP_X (point->X);
1540 point->Y = SWAP_Y (point->Y);
1542 END_LOOP;
1543 SetPolygonBoundingBox (polygon);
1544 r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
1545 /* hmmm, how to handle clip */
1547 ENDALL_LOOP;
1548 ALLTEXT_LOOP (Buffer->Data);
1550 r_delete_entry (layer->text_tree, (BoxType *)text);
1551 text->X = SWAP_X (text->X);
1552 text->Y = SWAP_Y (text->Y);
1553 TOGGLE_FLAG (ONSOLDERFLAG, text);
1554 SetTextBoundingBox (&PCB->Font, text);
1555 r_insert_entry (layer->text_tree, (BoxType *)text, 0);
1557 ENDALL_LOOP;
1558 /* swap silkscreen layers */
1559 swap = Buffer->Data->Layer[solder_silk_layer];
1560 Buffer->Data->Layer[solder_silk_layer] =
1561 Buffer->Data->Layer[component_silk_layer];
1562 Buffer->Data->Layer[component_silk_layer] = swap;
1564 /* swap layer groups when balanced */
1565 sgroup = GetLayerGroupNumberByNumber (solder_silk_layer);
1566 cgroup = GetLayerGroupNumberByNumber (component_silk_layer);
1567 if (PCB->LayerGroups.Number[cgroup] == PCB->LayerGroups.Number[sgroup])
1569 for (j = k = 0; j < PCB->LayerGroups.Number[sgroup]; j++)
1571 int t1, t2;
1572 Cardinal cnumber = PCB->LayerGroups.Entries[cgroup][k];
1573 Cardinal snumber = PCB->LayerGroups.Entries[sgroup][j];
1575 if (snumber >= max_copper_layer)
1576 continue;
1577 swap = Buffer->Data->Layer[snumber];
1579 while (cnumber >= max_copper_layer)
1581 k++;
1582 cnumber = PCB->LayerGroups.Entries[cgroup][k];
1584 Buffer->Data->Layer[snumber] = Buffer->Data->Layer[cnumber];
1585 Buffer->Data->Layer[cnumber] = swap;
1586 k++;
1587 /* move the thermal flags with the layers */
1588 ALLPIN_LOOP (Buffer->Data);
1590 t1 = TEST_THERM (snumber, pin);
1591 t2 = TEST_THERM (cnumber, pin);
1592 ASSIGN_THERM (snumber, t2, pin);
1593 ASSIGN_THERM (cnumber, t1, pin);
1595 ENDALL_LOOP;
1596 VIA_LOOP (Buffer->Data);
1598 t1 = TEST_THERM (snumber, via);
1599 t2 = TEST_THERM (cnumber, via);
1600 ASSIGN_THERM (snumber, t2, via);
1601 ASSIGN_THERM (cnumber, t1, via);
1603 END_LOOP;
1606 SetBufferBoundingBox (Buffer);
1607 SetCrosshairRangeToBuffer ();
1610 /* ----------------------------------------------------------------------
1611 * moves the passed object to the passed buffer and removes it
1612 * from its original place
1614 void *
1615 MoveObjectToBuffer (DataType *Destination, DataType *Src,
1616 int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1618 /* setup local identifiers used by move operations */
1619 Dest = Destination;
1620 Source = Src;
1621 return (ObjectOperation (&MoveBufferFunctions, Type, Ptr1, Ptr2, Ptr3));
1624 /* ----------------------------------------------------------------------
1625 * Adds the passed object to the passed buffer
1627 void *
1628 CopyObjectToBuffer (DataType *Destination, DataType *Src,
1629 int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1631 /* setup local identifiers used by Add operations */
1632 Dest = Destination;
1633 Source = Src;
1634 return (ObjectOperation (&AddBufferFunctions, Type, Ptr1, Ptr2, Ptr3));
1637 /* ---------------------------------------------------------------------- */
1639 HID_Action rotate_action_list[] = {
1640 {"FreeRotateBuffer", 0, ActionFreeRotateBuffer,
1641 freerotatebuffer_syntax, freerotatebuffer_help},
1642 {"LoadFootprint", 0, LoadFootprint,
1643 0,0}
1646 REGISTER_ACTIONS (rotate_action_list)