AddElementToBuffer(): Let CopyElementLowLevel() create the element to copy into.
[geda-pcb/pcjc2.git] / src / buffer.c
blob58357882f841d825f2d3486595c3e32ee235d54c
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 return CopyElementLowLevel (Dest, NULL, Element, false, 0, 0, FOUNDFLAG | ExtraFlag);
217 /* ---------------------------------------------------------------------------
218 * moves a via to paste buffer without allocating memory for the name
220 static void *
221 MoveViaToBuffer (PinType *via)
223 RestoreToPolygon (Source, VIA_TYPE, via, via);
225 r_delete_entry (Source->via_tree, (BoxType *) via);
226 Source->Via = g_list_remove (Source->Via, via);
227 Source->ViaN --;
228 Dest->Via = g_list_append (Dest->Via, via);
229 Dest->ViaN ++;
231 CLEAR_FLAG (WARNFLAG | FOUNDFLAG, via);
233 if (!Dest->via_tree)
234 Dest->via_tree = r_create_tree (NULL, 0, 0);
235 r_insert_entry (Dest->via_tree, (BoxType *)via, 0);
236 ClearFromPolygon (Dest, VIA_TYPE, via, via);
237 return via;
240 /* ---------------------------------------------------------------------------
241 * moves a rat-line to paste buffer
243 static void *
244 MoveRatToBuffer (RatType *rat)
246 r_delete_entry (Source->rat_tree, (BoxType *)rat);
248 Source->Rat = g_list_remove (Source->Rat, rat);
249 Source->RatN --;
250 Dest->Rat = g_list_append (Dest->Rat, rat);
251 Dest->RatN ++;
253 CLEAR_FLAG (FOUNDFLAG, rat);
255 if (!Dest->rat_tree)
256 Dest->rat_tree = r_create_tree (NULL, 0, 0);
257 r_insert_entry (Dest->rat_tree, (BoxType *)rat, 0);
258 return rat;
261 /* ---------------------------------------------------------------------------
262 * moves a line to buffer
264 static void *
265 MoveLineToBuffer (LayerType *layer, LineType *line)
267 LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
269 RestoreToPolygon (Source, LINE_TYPE, layer, line);
270 r_delete_entry (layer->line_tree, (BoxType *)line);
272 layer->Line = g_list_remove (layer->Line, line);
273 layer->LineN --;
274 lay->Line = g_list_append (lay->Line, line);
275 lay->LineN ++;
277 CLEAR_FLAG (FOUNDFLAG, line);
279 if (!lay->line_tree)
280 lay->line_tree = r_create_tree (NULL, 0, 0);
281 r_insert_entry (lay->line_tree, (BoxType *)line, 0);
282 ClearFromPolygon (Dest, LINE_TYPE, lay, line);
283 return (line);
286 /* ---------------------------------------------------------------------------
287 * moves an arc to buffer
289 static void *
290 MoveArcToBuffer (LayerType *layer, ArcType *arc)
292 LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
294 RestoreToPolygon (Source, ARC_TYPE, layer, arc);
295 r_delete_entry (layer->arc_tree, (BoxType *)arc);
297 layer->Arc = g_list_remove (layer->Arc, arc);
298 layer->ArcN --;
299 lay->Arc = g_list_append (lay->Arc, arc);
300 lay->ArcN ++;
302 CLEAR_FLAG (FOUNDFLAG, arc);
304 if (!lay->arc_tree)
305 lay->arc_tree = r_create_tree (NULL, 0, 0);
306 r_insert_entry (lay->arc_tree, (BoxType *)arc, 0);
307 ClearFromPolygon (Dest, ARC_TYPE, lay, arc);
308 return (arc);
311 /* ---------------------------------------------------------------------------
312 * moves a text to buffer without allocating memory for the name
314 static void *
315 MoveTextToBuffer (LayerType *layer, TextType *text)
317 LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
319 r_delete_entry (layer->text_tree, (BoxType *)text);
320 RestoreToPolygon (Source, TEXT_TYPE, layer, text);
322 layer->Text = g_list_remove (layer->Text, text);
323 layer->TextN --;
324 lay->Text = g_list_append (lay->Text, text);
325 lay->TextN ++;
327 if (!lay->text_tree)
328 lay->text_tree = r_create_tree (NULL, 0, 0);
329 r_insert_entry (lay->text_tree, (BoxType *)text, 0);
330 ClearFromPolygon (Dest, TEXT_TYPE, lay, text);
331 return (text);
334 /* ---------------------------------------------------------------------------
335 * moves a polygon to buffer. Doesn't allocate memory for the points
337 static void *
338 MovePolygonToBuffer (LayerType *layer, PolygonType *polygon)
340 LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
342 r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
344 layer->Polygon = g_list_remove (layer->Polygon, polygon);
345 layer->PolygonN --;
346 lay->Polygon = g_list_append (lay->Polygon, polygon);
347 lay->PolygonN ++;
349 CLEAR_FLAG (FOUNDFLAG, polygon);
351 if (!lay->polygon_tree)
352 lay->polygon_tree = r_create_tree (NULL, 0, 0);
353 r_insert_entry (lay->polygon_tree, (BoxType *)polygon, 0);
354 return (polygon);
357 /* ---------------------------------------------------------------------------
358 * moves a element to buffer without allocating memory for pins/names
360 static void *
361 MoveElementToBuffer (ElementType *element)
364 * Delete the element from the source (remove it from trees,
365 * restore to polygons)
367 r_delete_element (Source, element);
369 Source->Element = g_list_remove (Source->Element, element);
370 Source->ElementN --;
371 Dest->Element = g_list_append (Dest->Element, element);
372 Dest->ElementN ++;
374 PIN_LOOP (element);
376 RestoreToPolygon(Source, PIN_TYPE, element, pin);
377 CLEAR_FLAG (WARNFLAG | FOUNDFLAG, pin);
379 END_LOOP;
380 PAD_LOOP (element);
382 RestoreToPolygon(Source, PAD_TYPE, element, pad);
383 CLEAR_FLAG (WARNFLAG | FOUNDFLAG, pad);
385 END_LOOP;
386 SetElementBoundingBox (Dest, element, &PCB->Font);
388 * Now clear the from the polygons in the destination
390 PIN_LOOP (element);
392 ClearFromPolygon (Dest, PIN_TYPE, element, pin);
394 END_LOOP;
395 PAD_LOOP (element);
397 ClearFromPolygon (Dest, PAD_TYPE, element, pad);
399 END_LOOP;
401 return element;
404 /* ---------------------------------------------------------------------------
405 * calculates the bounding box of the buffer
407 void
408 SetBufferBoundingBox (BufferType *Buffer)
410 BoxType *box = GetDataBoundingBox (Buffer->Data);
412 if (box)
413 Buffer->BoundingBox = *box;
416 /* ---------------------------------------------------------------------------
417 * clears the contents of the paste buffer
419 void
420 ClearBuffer (BufferType *Buffer)
422 if (Buffer && Buffer->Data)
424 FreeDataMemory (Buffer->Data);
425 Buffer->Data->pcb = PCB;
429 /* ----------------------------------------------------------------------
430 * copies all selected and visible objects to the paste buffer
431 * returns true if any objects have been removed
433 void
434 AddSelectedToBuffer (BufferType *Buffer, Coord X, Coord Y, bool LeaveSelected)
436 /* switch crosshair off because adding objects to the pastebuffer
437 * may change the 'valid' area for the cursor
439 if (!LeaveSelected)
440 ExtraFlag = SELECTEDFLAG;
441 notify_crosshair_change (false);
442 Source = PCB->Data;
443 Dest = Buffer->Data;
444 SelectedOperation (&AddBufferFunctions, false, ALL_TYPES);
446 /* set origin to passed or current position */
447 if (X || Y)
449 Buffer->X = X;
450 Buffer->Y = Y;
452 else
454 Buffer->X = Crosshair.X;
455 Buffer->Y = Crosshair.Y;
457 notify_crosshair_change (true);
458 ExtraFlag = 0;
461 /* ---------------------------------------------------------------------------
462 * loads element data from file/library into buffer
463 * parse the file with disabled 'PCB mode' (see parser)
464 * returns false on error
465 * if successful, update some other stuff and reposition the pastebuffer
467 bool
468 LoadElementToBuffer (BufferType *Buffer, char *Name, bool FromFile)
470 ElementType *element;
472 ClearBuffer (Buffer);
473 if (FromFile)
475 if (!ParseElementFile (Buffer->Data, Name))
477 if (Settings.ShowSolderSide)
478 SwapBuffer (Buffer);
479 SetBufferBoundingBox (Buffer);
480 if (Buffer->Data->ElementN)
482 element = Buffer->Data->Element->data;
483 Buffer->X = element->MarkX;
484 Buffer->Y = element->MarkY;
486 else
488 Buffer->X = 0;
489 Buffer->Y = 0;
491 return (true);
494 else
496 if (!ParseLibraryEntry (Buffer->Data, Name)
497 && Buffer->Data->ElementN != 0)
499 element = Buffer->Data->Element->data;
501 /* always add elements using top-side coordinates */
502 if (Settings.ShowSolderSide)
503 MirrorElementCoordinates (Buffer->Data, element, 0);
504 SetElementBoundingBox (Buffer->Data, element, &PCB->Font);
506 /* set buffer offset to 'mark' position */
507 Buffer->X = element->MarkX;
508 Buffer->Y = element->MarkY;
509 SetBufferBoundingBox (Buffer);
510 return (true);
513 /* release memory which might have been acquired */
514 ClearBuffer (Buffer);
515 return (false);
519 /*---------------------------------------------------------------------------
520 * Searches for the given element by "footprint" name, and loads it
521 * into the buffer.
524 /* Figuring out which library entry is the one we want is a little
525 tricky. For file-based footprints, it's just a matter of finding
526 the first match in the search list. For m4-based footprints you
527 need to know what magic to pass to the m4 functions. Fortunately,
528 the footprint needed is determined when we build the m4 libraries
529 and stored as a comment in the description, so we can search for
530 that to find the magic we need. We use a hash to store the
531 corresponding footprints and pointers to the library tree so we can
532 quickly find the various bits we need to load a given
533 footprint. */
535 typedef struct {
536 char *footprint;
537 int footprint_allocated;
538 int menu_idx;
539 int entry_idx;
540 } FootprintHashEntry;
542 static FootprintHashEntry *footprint_hash = 0;
543 int footprint_hash_size = 0;
545 void
546 clear_footprint_hash ()
548 int i;
549 if (!footprint_hash)
550 return;
551 for (i=0; i<footprint_hash_size; i++)
552 if (footprint_hash[i].footprint_allocated)
553 free (footprint_hash[i].footprint);
554 free (footprint_hash);
555 footprint_hash = NULL;
556 footprint_hash_size = 0;
559 /* Used to sort footprint pointer entries. Note we include the index
560 numbers so that same-named footprints are sorted by the library
561 search order. */
562 static int
563 footprint_hash_cmp (const void *va, const void *vb)
565 int i;
566 FootprintHashEntry *a = (FootprintHashEntry *)va;
567 FootprintHashEntry *b = (FootprintHashEntry *)vb;
569 i = strcmp (a->footprint, b->footprint);
570 if (i == 0)
571 i = a->menu_idx - b->menu_idx;
572 if (i == 0)
573 i = a->entry_idx - b->entry_idx;
574 return i;
577 void
578 make_footprint_hash ()
580 int i, j;
581 char *fp;
582 int num_entries = 0;
584 clear_footprint_hash ();
586 for (i=0; i<Library.MenuN; i++)
587 for (j=0; j<Library.Menu[i].EntryN; j++)
588 num_entries ++;
589 footprint_hash = (FootprintHashEntry *)malloc (num_entries * sizeof(FootprintHashEntry));
590 num_entries = 0;
592 /* There are two types of library entries. The file-based types
593 have a Template of (char *)-1 and the AllocatedMemory is the full
594 path to the footprint file. The m4 ones have the footprint name
595 in brackets in the description. */
596 for (i=0; i<Library.MenuN; i++)
598 #ifdef DEBUG
599 printf("In make_footprint_hash, looking for footprints in %s\n",
600 Library.Menu[i].directory);
601 #endif
603 for (j=0; j<Library.Menu[i].EntryN; j++)
605 footprint_hash[num_entries].menu_idx = i;
606 footprint_hash[num_entries].entry_idx = j;
607 if (Library.Menu[i].Entry[j].Template == (char *) -1)
608 /* file */
610 #ifdef DEBUG
611 /* printf(" ... Examining file %s\n", Library.Menu[i].Entry[j].AllocatedMemory); */
612 #endif
613 fp = strrchr (Library.Menu[i].Entry[j].AllocatedMemory, '/');
615 if (!fp)
616 fp = strrchr (Library.Menu[i].Entry[j].AllocatedMemory, '\\');
618 if (fp)
619 fp ++;
620 else
621 fp = Library.Menu[i].Entry[j].AllocatedMemory;
623 #ifdef DEBUG
624 /* printf(" ... found file footprint %s\n", fp); */
625 #endif
627 footprint_hash[num_entries].footprint = fp;
628 footprint_hash[num_entries].footprint_allocated = 0;
630 else
631 /* m4 */
633 fp = strrchr (Library.Menu[i].Entry[j].Description, '[');
634 if (fp)
636 footprint_hash[num_entries].footprint = strdup (fp+1);
637 footprint_hash[num_entries].footprint_allocated = 1;
638 fp = strchr (footprint_hash[num_entries].footprint, ']');
639 if (fp)
640 *fp = 0;
642 else
644 fp = Library.Menu[i].Entry[j].Description;
645 footprint_hash[num_entries].footprint = fp;
646 footprint_hash[num_entries].footprint_allocated = 0;
649 num_entries ++;
653 footprint_hash_size = num_entries;
654 qsort (footprint_hash, num_entries, sizeof(footprint_hash[0]), footprint_hash_cmp);
656 #ifdef DEBUG
657 printf(" found footprints: \n");
658 for (i=0; i<num_entries; i++)
659 printf("[%s]\n", footprint_hash[i].footprint);
660 #endif
664 FootprintHashEntry *
665 search_footprint_hash (const char *footprint)
667 int i, min, max, c;
669 /* Standard binary search */
671 min = -1;
672 max = footprint_hash_size;
674 while (max - min > 1)
676 i = (min+max)/2;
677 c = strcmp (footprint, footprint_hash[i].footprint);
678 if (c < 0)
679 max = i;
680 else if (c > 0)
681 min = i;
682 else
684 /* We want to return the first match, not just any match. */
685 while (i > 0
686 && strcmp (footprint, footprint_hash[i-1].footprint) == 0)
687 i--;
688 return & footprint_hash[i];
691 return NULL;
694 /* Returns zero on success, non-zero on error. */
696 LoadFootprintByName (BufferType *Buffer, char *Footprint)
698 int i;
699 FootprintHashEntry *fpe;
700 LibraryMenuType *menu;
701 LibraryEntryType *entry;
702 char *with_fp = NULL;
704 if (!footprint_hash)
705 make_footprint_hash ();
707 fpe = search_footprint_hash (Footprint);
708 if (!fpe)
710 with_fp = Concat (Footprint, ".fp", NULL);
711 fpe = search_footprint_hash (with_fp);
712 if (fpe)
713 Footprint = with_fp;
715 if (!fpe)
717 Message("Unable to load footprint %s\n", Footprint);
718 return 1;
721 menu = & Library.Menu[fpe->menu_idx];
722 entry = & menu->Entry[fpe->entry_idx];
724 if (entry->Template == (char *) -1)
726 i = LoadElementToBuffer (Buffer, entry->AllocatedMemory, true);
727 if (with_fp)
728 free (with_fp);
729 return i ? 0 : 1;
731 else
733 char *args;
735 args = Concat("'", EMPTY (entry->Template), "' '",
736 EMPTY (entry->Value), "' '", EMPTY (entry->Package), "'", NULL);
737 i = LoadElementToBuffer (Buffer, args, false);
739 free (args);
740 if (with_fp)
741 free (with_fp);
742 return i ? 0 : 1;
745 #ifdef DEBUG
747 int j;
748 printf("Library path: %s\n", Settings.LibraryPath);
749 printf("Library tree: %s\n", Settings.LibraryTree);
751 printf("Library:\n");
752 for (i=0; i<Library.MenuN; i++)
754 printf(" [%02d] Name: %s\n", i, Library.Menu[i].Name);
755 printf(" Dir: %s\n", Library.Menu[i].directory);
756 printf(" Sty: %s\n", Library.Menu[i].Style);
757 for (j=0; j<Library.Menu[i].EntryN; j++)
759 printf(" [%02d] E: %s\n", j, Library.Menu[i].Entry[j].ListEntry);
760 if (Library.Menu[i].Entry[j].Template == (char *) -1)
761 printf(" A: %s\n", Library.Menu[i].Entry[j].AllocatedMemory);
762 else
764 printf(" T: %s\n", Library.Menu[i].Entry[j].Template);
765 printf(" P: %s\n", Library.Menu[i].Entry[j].Package);
766 printf(" V: %s\n", Library.Menu[i].Entry[j].Value);
767 printf(" D: %s\n", Library.Menu[i].Entry[j].Description);
769 if (j == 10)
770 break;
774 #endif
778 static const char loadfootprint_syntax[] = "LoadFootprint(filename[,refdes,value])";
780 static const char loadfootprint_help[] = "Loads a single footprint by name.";
782 /* %start-doc actions LoadFootprint
784 Loads a single footprint by name, rather than by reference or through
785 the library. If a refdes and value are specified, those are inserted
786 into the footprint as well. The footprint remains in the paste buffer.
788 %end-doc */
791 LoadFootprint (int argc, char **argv, Coord x, Coord y)
793 char *name = ARG(0);
794 char *refdes = ARG(1);
795 char *value = ARG(2);
796 ElementType *e;
798 if (!name)
799 AFAIL (loadfootprint);
801 if (LoadFootprintByName (PASTEBUFFER, name))
802 return 1;
804 if (PASTEBUFFER->Data->ElementN == 0)
806 Message("Footprint %s contains no elements", name);
807 return 1;
809 if (PASTEBUFFER->Data->ElementN > 1)
811 Message("Footprint %s contains multiple elements", name);
812 return 1;
815 e = PASTEBUFFER->Data->Element->data;
817 if (e->Name[0].TextString)
818 free (e->Name[0].TextString);
819 e->Name[0].TextString = strdup (name);
821 if (e->Name[1].TextString)
822 free (e->Name[1].TextString);
823 e->Name[1].TextString = refdes ? strdup (refdes) : 0;
825 if (e->Name[2].TextString)
826 free (e->Name[2].TextString);
827 e->Name[2].TextString = value ? strdup (value) : 0;
829 return 0;
832 /*---------------------------------------------------------------------------
834 * break buffer element into pieces
836 bool
837 SmashBufferElement (BufferType *Buffer)
839 ElementType *element;
840 Cardinal group;
841 LayerType *clayer, *slayer;
843 if (Buffer->Data->ElementN != 1)
845 Message (_("Error! Buffer doesn't contain a single element\n"));
846 return (false);
849 * At this point the buffer should contain just a single element.
850 * Now we detach the single element from the buffer and then clear the
851 * buffer, ready to receive the smashed elements. As a result of detaching
852 * it the single element is orphaned from the buffer and thus will not be
853 * free()'d by FreeDataMemory (called via ClearBuffer). This leaves it
854 * around for us to smash bits off it. It then becomes our responsibility,
855 * however, to free the single element when we're finished with it.
857 element = Buffer->Data->Element->data;
858 Buffer->Data->Element = NULL;
859 Buffer->Data->ElementN = 0;
860 ClearBuffer (Buffer);
861 ELEMENTLINE_LOOP (element);
863 CreateNewLineOnLayer (&Buffer->Data->SILKLAYER,
864 line->Point1.X, line->Point1.Y,
865 line->Point2.X, line->Point2.Y,
866 line->Thickness, 0, NoFlags ());
867 if (line)
868 line->Number = STRDUP (NAMEONPCB_NAME (element));
870 END_LOOP;
871 ARC_LOOP (element);
873 CreateNewArcOnLayer (&Buffer->Data->SILKLAYER,
874 arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle,
875 arc->Delta, arc->Thickness, 0, NoFlags ());
877 END_LOOP;
878 PIN_LOOP (element);
880 FlagType f = NoFlags ();
881 AddFlags (f, VIAFLAG);
882 if (TEST_FLAG (HOLEFLAG, pin))
883 AddFlags (f, HOLEFLAG);
885 CreateNewVia (Buffer->Data, pin->X, pin->Y,
886 pin->Thickness, pin->Clearance, pin->Mask,
887 pin->DrillingHole, pin->Number, f);
889 END_LOOP;
890 group =
891 GetLayerGroupNumberByNumber (SWAP_IDENT ? solder_silk_layer :
892 component_silk_layer);
893 clayer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
894 group =
895 GetLayerGroupNumberByNumber (SWAP_IDENT ? component_silk_layer :
896 solder_silk_layer);
897 slayer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
898 PAD_LOOP (element);
900 LineType *line;
901 line = CreateNewLineOnLayer (TEST_FLAG (ONSOLDERFLAG, pad) ? slayer : clayer,
902 pad->Point1.X, pad->Point1.Y,
903 pad->Point2.X, pad->Point2.Y,
904 pad->Thickness, pad->Clearance, NoFlags ());
905 if (line)
906 line->Number = STRDUP (pad->Number);
908 END_LOOP;
909 FreeElementMemory (element);
910 g_slice_free (ElementType, element);
911 return (true);
914 /*---------------------------------------------------------------------------
916 * see if a polygon is a rectangle. If so, canonicalize it.
919 static int
920 polygon_is_rectangle (PolygonType *poly)
922 int i, best;
923 PointType temp[4];
924 if (poly->PointN != 4 || poly->HoleIndexN != 0)
925 return 0;
926 best = 0;
927 for (i=1; i<4; i++)
928 if (poly->Points[i].X < poly->Points[best].X
929 || poly->Points[i].Y < poly->Points[best].Y)
930 best = i;
931 for (i=0; i<4; i++)
932 temp[i] = poly->Points[(i+best)%4];
933 if (temp[0].X == temp[1].X)
934 memcpy (poly->Points, temp, sizeof(temp));
935 else
937 /* reverse them */
938 poly->Points[0] = temp[0];
939 poly->Points[1] = temp[3];
940 poly->Points[2] = temp[2];
941 poly->Points[3] = temp[1];
943 if (poly->Points[0].X == poly->Points[1].X
944 && poly->Points[1].Y == poly->Points[2].Y
945 && poly->Points[2].X == poly->Points[3].X
946 && poly->Points[3].Y == poly->Points[0].Y)
947 return 1;
948 return 0;
951 /*---------------------------------------------------------------------------
953 * convert buffer contents into an element
955 bool
956 ConvertBufferToElement (BufferType *Buffer)
958 ElementType *Element;
959 Cardinal group;
960 Cardinal pin_n = 1;
961 bool hasParts = false, crooked = false;
962 int onsolder;
963 bool warned = false;
965 if (Buffer->Data->pcb == 0)
966 Buffer->Data->pcb = PCB;
968 Element = CreateNewElement (PCB->Data, NULL, &PCB->Font, NoFlags (),
969 NULL, NULL, NULL, PASTEBUFFER->X,
970 PASTEBUFFER->Y, 0, 100,
971 MakeFlags (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG),
972 false);
973 if (!Element)
974 return (false);
975 VIA_LOOP (Buffer->Data);
977 char num[8];
978 if (via->Mask < via->Thickness)
979 via->Mask = via->Thickness + 2 * MASKFRAME;
980 if (via->Name)
981 CreateNewPin (Element, via->X, via->Y, via->Thickness,
982 via->Clearance, via->Mask, via->DrillingHole,
983 NULL, via->Name, MaskFlags (via->Flags,
984 VIAFLAG | FOUNDFLAG |
985 SELECTEDFLAG | WARNFLAG));
986 else
988 sprintf (num, "%d", pin_n++);
989 CreateNewPin (Element, via->X, via->Y, via->Thickness,
990 via->Clearance, via->Mask, via->DrillingHole,
991 NULL, num, MaskFlags (via->Flags,
992 VIAFLAG | FOUNDFLAG | SELECTEDFLAG
993 | WARNFLAG));
995 hasParts = true;
997 END_LOOP;
999 for (onsolder = 0; onsolder < 2; onsolder ++)
1001 int silk_layer;
1002 int onsolderflag;
1004 if ((!onsolder) == (!SWAP_IDENT))
1006 silk_layer = component_silk_layer;
1007 onsolderflag = NOFLAG;
1009 else
1011 silk_layer = solder_silk_layer;
1012 onsolderflag = ONSOLDERFLAG;
1015 #define MAYBE_WARN() \
1016 if (onsolder && !hasParts && !warned) \
1018 warned = true; \
1019 Message \
1020 (_("Warning: All of the pads are on the opposite\n" \
1021 "side from the component - that's probably not what\n" \
1022 "you wanted\n")); \
1025 /* get the component-side SM pads */
1026 group = GetLayerGroupNumberByNumber (silk_layer);
1027 GROUP_LOOP (Buffer->Data, group);
1029 char num[8];
1030 LINE_LOOP (layer);
1032 sprintf (num, "%d", pin_n++);
1033 CreateNewPad (Element, line->Point1.X,
1034 line->Point1.Y, line->Point2.X,
1035 line->Point2.Y, line->Thickness,
1036 line->Clearance,
1037 line->Thickness + line->Clearance, NULL,
1038 line->Number ? line->Number : num,
1039 MakeFlags (onsolderflag));
1040 MAYBE_WARN();
1041 hasParts = true;
1043 END_LOOP;
1044 POLYGON_LOOP (layer);
1046 Coord x1, y1, x2, y2, w, h, t;
1048 if (! polygon_is_rectangle (polygon))
1050 crooked = true;
1051 continue;
1054 w = polygon->Points[2].X - polygon->Points[0].X;
1055 h = polygon->Points[1].Y - polygon->Points[0].Y;
1056 t = (w < h) ? w : h;
1057 x1 = polygon->Points[0].X + t/2;
1058 y1 = polygon->Points[0].Y + t/2;
1059 x2 = x1 + (w-t);
1060 y2 = y1 + (h-t);
1062 sprintf (num, "%d", pin_n++);
1063 CreateNewPad (Element,
1064 x1, y1, x2, y2, t,
1065 2 * Settings.Keepaway,
1066 t + Settings.Keepaway,
1067 NULL, num,
1068 MakeFlags (SQUAREFLAG | onsolderflag));
1069 MAYBE_WARN();
1070 hasParts = true;
1072 END_LOOP;
1074 END_LOOP;
1077 /* now add the silkscreen. NOTE: elements must have pads or pins too */
1078 LINE_LOOP (&Buffer->Data->SILKLAYER);
1080 if (line->Number && !NAMEONPCB_NAME (Element))
1081 NAMEONPCB_NAME (Element) = strdup (line->Number);
1082 CreateNewLineInElement (Element, line->Point1.X,
1083 line->Point1.Y, line->Point2.X,
1084 line->Point2.Y, line->Thickness);
1085 hasParts = true;
1087 END_LOOP;
1088 ARC_LOOP (&Buffer->Data->SILKLAYER);
1090 CreateNewArcInElement (Element, arc->X, arc->Y, arc->Width,
1091 arc->Height, arc->StartAngle, arc->Delta,
1092 arc->Thickness);
1093 hasParts = true;
1095 END_LOOP;
1096 if (!hasParts)
1098 DestroyObject (PCB->Data, ELEMENT_TYPE, Element, Element, Element);
1099 Message (_("There was nothing to convert!\n"
1100 "Elements must have some silk, pads or pins.\n"));
1101 return (false);
1103 if (crooked)
1104 Message (_("There were polygons that can't be made into pins!\n"
1105 "So they were not included in the element\n"));
1106 Element->MarkX = Buffer->X;
1107 Element->MarkY = Buffer->Y;
1108 if (SWAP_IDENT)
1109 SET_FLAG (ONSOLDERFLAG, Element);
1110 SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
1111 ClearBuffer (Buffer);
1112 MoveObjectToBuffer (Buffer->Data, PCB->Data, ELEMENT_TYPE, Element, Element,
1113 Element);
1114 SetBufferBoundingBox (Buffer);
1115 return (true);
1118 /* ---------------------------------------------------------------------------
1119 * load PCB into buffer
1120 * parse the file with enabled 'PCB mode' (see parser)
1121 * if successful, update some other stuff
1123 bool
1124 LoadLayoutToBuffer (BufferType *Buffer, char *Filename)
1126 PCBType *newPCB = CreateNewPCB (false);
1128 /* new data isn't added to the undo list */
1129 if (!ParsePCB (newPCB, Filename))
1131 /* clear data area and replace pointer */
1132 ClearBuffer (Buffer);
1133 free (Buffer->Data);
1134 Buffer->Data = newPCB->Data;
1135 newPCB->Data = NULL;
1136 Buffer->X = newPCB->CursorX;
1137 Buffer->Y = newPCB->CursorY;
1138 RemovePCB (newPCB);
1139 Buffer->Data->pcb = PCB;
1140 return (true);
1143 /* release unused memory */
1144 RemovePCB (newPCB);
1145 Buffer->Data->pcb = PCB;
1146 return (false);
1149 /* ---------------------------------------------------------------------------
1150 * rotates the contents of the pastebuffer
1152 void
1153 RotateBuffer (BufferType *Buffer, BYTE Number)
1155 /* rotate vias */
1156 VIA_LOOP (Buffer->Data);
1158 r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
1159 ROTATE_VIA_LOWLEVEL (via, Buffer->X, Buffer->Y, Number);
1160 SetPinBoundingBox (via);
1161 r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
1163 END_LOOP;
1165 /* elements */
1166 ELEMENT_LOOP (Buffer->Data);
1168 RotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
1169 Number);
1171 END_LOOP;
1173 /* all layer related objects */
1174 ALLLINE_LOOP (Buffer->Data);
1176 r_delete_entry (layer->line_tree, (BoxType *)line);
1177 RotateLineLowLevel (line, Buffer->X, Buffer->Y, Number);
1178 r_insert_entry (layer->line_tree, (BoxType *)line, 0);
1180 ENDALL_LOOP;
1181 ALLARC_LOOP (Buffer->Data);
1183 r_delete_entry (layer->arc_tree, (BoxType *)arc);
1184 RotateArcLowLevel (arc, Buffer->X, Buffer->Y, Number);
1185 r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
1187 ENDALL_LOOP;
1188 ALLTEXT_LOOP (Buffer->Data);
1190 r_delete_entry (layer->text_tree, (BoxType *)text);
1191 RotateTextLowLevel (text, Buffer->X, Buffer->Y, Number);
1192 r_insert_entry (layer->text_tree, (BoxType *)text, 0);
1194 ENDALL_LOOP;
1195 ALLPOLYGON_LOOP (Buffer->Data);
1197 r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
1198 RotatePolygonLowLevel (polygon, Buffer->X, Buffer->Y, Number);
1199 r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
1201 ENDALL_LOOP;
1203 /* finally the origin and the bounding box */
1204 ROTATE (Buffer->X, Buffer->Y, Buffer->X, Buffer->Y, Number);
1205 RotateBoxLowLevel (&Buffer->BoundingBox, Buffer->X, Buffer->Y, Number);
1206 SetCrosshairRangeToBuffer ();
1209 static void
1210 free_rotate (Coord *x, Coord *y, Coord cx, Coord cy, double cosa, double sina)
1212 double nx, ny;
1213 Coord px = *x - cx;
1214 Coord py = *y - cy;
1216 nx = px * cosa + py * sina;
1217 ny = py * cosa - px * sina;
1219 *x = nx + cx;
1220 *y = ny + cy;
1223 void
1224 FreeRotateElementLowLevel (DataType *Data, ElementType *Element,
1225 Coord X, Coord Y,
1226 double cosa, double sina, Angle angle)
1228 /* solder side objects need a different orientation */
1230 /* the text subroutine decides by itself if the direction
1231 * is to be corrected
1233 #if 0
1234 ELEMENTTEXT_LOOP (Element);
1236 if (Data && Data->name_tree[n])
1237 r_delete_entry (Data->name_tree[n], (BoxType *)text);
1238 RotateTextLowLevel (text, X, Y, Number);
1240 END_LOOP;
1241 #endif
1242 ELEMENTLINE_LOOP (Element);
1244 free_rotate (&line->Point1.X, &line->Point1.Y, X, Y, cosa, sina);
1245 free_rotate (&line->Point2.X, &line->Point2.Y, X, Y, cosa, sina);
1246 SetLineBoundingBox (line);
1248 END_LOOP;
1249 PIN_LOOP (Element);
1251 /* pre-delete the pins from the pin-tree before their coordinates change */
1252 if (Data)
1253 r_delete_entry (Data->pin_tree, (BoxType *)pin);
1254 RestoreToPolygon (Data, PIN_TYPE, Element, pin);
1255 free_rotate (&pin->X, &pin->Y, X, Y, cosa, sina);
1256 SetPinBoundingBox (pin);
1258 END_LOOP;
1259 PAD_LOOP (Element);
1261 /* pre-delete the pads before their coordinates change */
1262 if (Data)
1263 r_delete_entry (Data->pad_tree, (BoxType *)pad);
1264 RestoreToPolygon (Data, PAD_TYPE, Element, pad);
1265 free_rotate (&pad->Point1.X, &pad->Point1.Y, X, Y, cosa, sina);
1266 free_rotate (&pad->Point2.X, &pad->Point2.Y, X, Y, cosa, sina);
1267 SetLineBoundingBox ((LineType *) pad);
1269 END_LOOP;
1270 ARC_LOOP (Element);
1272 free_rotate (&arc->X, &arc->Y, X, Y, cosa, sina);
1273 arc->StartAngle = NormalizeAngle (arc->StartAngle + angle);
1275 END_LOOP;
1277 free_rotate (&Element->MarkX, &Element->MarkY, X, Y, cosa, sina);
1278 SetElementBoundingBox (Data, Element, &PCB->Font);
1279 ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element);
1282 void
1283 FreeRotateBuffer (BufferType *Buffer, Angle angle)
1285 double cosa, sina;
1287 cosa = cos(angle * M_PI/180.0);
1288 sina = sin(angle * M_PI/180.0);
1290 /* rotate vias */
1291 VIA_LOOP (Buffer->Data);
1293 r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
1294 free_rotate (&via->X, &via->Y, Buffer->X, Buffer->Y, cosa, sina);
1295 SetPinBoundingBox (via);
1296 r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
1298 END_LOOP;
1300 /* elements */
1301 ELEMENT_LOOP (Buffer->Data);
1303 FreeRotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
1304 cosa, sina, angle);
1306 END_LOOP;
1308 /* all layer related objects */
1309 ALLLINE_LOOP (Buffer->Data);
1311 r_delete_entry (layer->line_tree, (BoxType *)line);
1312 free_rotate (&line->Point1.X, &line->Point1.Y, Buffer->X, Buffer->Y, cosa, sina);
1313 free_rotate (&line->Point2.X, &line->Point2.Y, Buffer->X, Buffer->Y, cosa, sina);
1314 SetLineBoundingBox (line);
1315 r_insert_entry (layer->line_tree, (BoxType *)line, 0);
1317 ENDALL_LOOP;
1318 ALLARC_LOOP (Buffer->Data);
1320 r_delete_entry (layer->arc_tree, (BoxType *)arc);
1321 free_rotate (&arc->X, &arc->Y, Buffer->X, Buffer->Y, cosa, sina);
1322 arc->StartAngle = NormalizeAngle (arc->StartAngle + angle);
1323 r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
1325 ENDALL_LOOP;
1326 /* FIXME: rotate text */
1327 ALLPOLYGON_LOOP (Buffer->Data);
1329 r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
1330 POLYGONPOINT_LOOP (polygon);
1332 free_rotate (&point->X, &point->Y, Buffer->X, Buffer->Y, cosa, sina);
1334 END_LOOP;
1335 SetPolygonBoundingBox (polygon);
1336 r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
1338 ENDALL_LOOP;
1340 SetBufferBoundingBox (Buffer);
1341 SetCrosshairRangeToBuffer ();
1345 /* -------------------------------------------------------------------------- */
1347 static const char freerotatebuffer_syntax[] =
1348 "FreeRotateBuffer([Angle])";
1350 static const char freerotatebuffer_help[] =
1351 "Rotates the current paste buffer contents by the specified angle. The\n"
1352 "angle is given in degrees. If no angle is given, the user is prompted\n"
1353 "for one.\n";
1355 /* %start-doc actions FreeRotateBuffer
1357 Rotates the contents of the pastebuffer by an arbitrary angle. If no
1358 angle is given, the user is prompted for one.
1360 %end-doc */
1363 ActionFreeRotateBuffer(int argc, char **argv, Coord x, Coord y)
1365 char *angle_s;
1367 if (argc < 1)
1368 angle_s = gui->prompt_for ("Enter Rotation (degrees, CCW):", "0");
1369 else
1370 angle_s = argv[0];
1372 notify_crosshair_change (false);
1373 FreeRotateBuffer(PASTEBUFFER, strtod(angle_s, 0));
1374 notify_crosshair_change (true);
1375 return 0;
1378 /* ---------------------------------------------------------------------------
1379 * initializes the buffers by allocating memory
1381 void
1382 InitBuffers (void)
1384 int i;
1386 for (i = 0; i < MAX_BUFFER; i++)
1387 Buffers[i].Data = CreateNewBuffer ();
1390 void
1391 SwapBuffers (void)
1393 int i;
1395 for (i = 0; i < MAX_BUFFER; i++)
1396 SwapBuffer (&Buffers[i]);
1397 SetCrosshairRangeToBuffer ();
1400 void
1401 MirrorBuffer (BufferType *Buffer)
1403 int i;
1405 if (Buffer->Data->ElementN)
1407 Message (_("You can't mirror a buffer that has elements!\n"));
1408 return;
1410 for (i = 0; i < max_copper_layer + 2; i++)
1412 LayerType *layer = Buffer->Data->Layer + i;
1413 if (layer->TextN)
1415 Message (_("You can't mirror a buffer that has text!\n"));
1416 return;
1419 /* set buffer offset to 'mark' position */
1420 Buffer->X = SWAP_X (Buffer->X);
1421 Buffer->Y = SWAP_Y (Buffer->Y);
1422 VIA_LOOP (Buffer->Data);
1424 via->X = SWAP_X (via->X);
1425 via->Y = SWAP_Y (via->Y);
1427 END_LOOP;
1428 ALLLINE_LOOP (Buffer->Data);
1430 line->Point1.X = SWAP_X (line->Point1.X);
1431 line->Point1.Y = SWAP_Y (line->Point1.Y);
1432 line->Point2.X = SWAP_X (line->Point2.X);
1433 line->Point2.Y = SWAP_Y (line->Point2.Y);
1435 ENDALL_LOOP;
1436 ALLARC_LOOP (Buffer->Data);
1438 arc->X = SWAP_X (arc->X);
1439 arc->Y = SWAP_Y (arc->Y);
1440 arc->StartAngle = SWAP_ANGLE (arc->StartAngle);
1441 arc->Delta = SWAP_DELTA (arc->Delta);
1442 SetArcBoundingBox (arc);
1444 ENDALL_LOOP;
1445 ALLPOLYGON_LOOP (Buffer->Data);
1447 POLYGONPOINT_LOOP (polygon);
1449 point->X = SWAP_X (point->X);
1450 point->Y = SWAP_Y (point->Y);
1452 END_LOOP;
1453 SetPolygonBoundingBox (polygon);
1455 ENDALL_LOOP;
1456 SetBufferBoundingBox (Buffer);
1457 SetCrosshairRangeToBuffer ();
1461 /* ---------------------------------------------------------------------------
1462 * flip components/tracks from one side to the other
1464 static void
1465 SwapBuffer (BufferType *Buffer)
1467 int j, k;
1468 Cardinal sgroup, cgroup;
1469 LayerType swap;
1471 ELEMENT_LOOP (Buffer->Data);
1473 r_delete_element (Buffer->Data, element);
1474 MirrorElementCoordinates (Buffer->Data, element, 0);
1476 END_LOOP;
1477 /* set buffer offset to 'mark' position */
1478 Buffer->X = SWAP_X (Buffer->X);
1479 Buffer->Y = SWAP_Y (Buffer->Y);
1480 VIA_LOOP (Buffer->Data);
1482 r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
1483 via->X = SWAP_X (via->X);
1484 via->Y = SWAP_Y (via->Y);
1485 SetPinBoundingBox (via);
1486 r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
1488 END_LOOP;
1489 ALLLINE_LOOP (Buffer->Data);
1491 r_delete_entry (layer->line_tree, (BoxType *)line);
1492 line->Point1.X = SWAP_X (line->Point1.X);
1493 line->Point1.Y = SWAP_Y (line->Point1.Y);
1494 line->Point2.X = SWAP_X (line->Point2.X);
1495 line->Point2.Y = SWAP_Y (line->Point2.Y);
1496 SetLineBoundingBox (line);
1497 r_insert_entry (layer->line_tree, (BoxType *)line, 0);
1499 ENDALL_LOOP;
1500 ALLARC_LOOP (Buffer->Data);
1502 r_delete_entry (layer->arc_tree, (BoxType *)arc);
1503 arc->X = SWAP_X (arc->X);
1504 arc->Y = SWAP_Y (arc->Y);
1505 arc->StartAngle = SWAP_ANGLE (arc->StartAngle);
1506 arc->Delta = SWAP_DELTA (arc->Delta);
1507 SetArcBoundingBox (arc);
1508 r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
1510 ENDALL_LOOP;
1511 ALLPOLYGON_LOOP (Buffer->Data);
1513 r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
1514 POLYGONPOINT_LOOP (polygon);
1516 point->X = SWAP_X (point->X);
1517 point->Y = SWAP_Y (point->Y);
1519 END_LOOP;
1520 SetPolygonBoundingBox (polygon);
1521 r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
1522 /* hmmm, how to handle clip */
1524 ENDALL_LOOP;
1525 ALLTEXT_LOOP (Buffer->Data);
1527 r_delete_entry (layer->text_tree, (BoxType *)text);
1528 text->X = SWAP_X (text->X);
1529 text->Y = SWAP_Y (text->Y);
1530 TOGGLE_FLAG (ONSOLDERFLAG, text);
1531 SetTextBoundingBox (&PCB->Font, text);
1532 r_insert_entry (layer->text_tree, (BoxType *)text, 0);
1534 ENDALL_LOOP;
1535 /* swap silkscreen layers */
1536 swap = Buffer->Data->Layer[solder_silk_layer];
1537 Buffer->Data->Layer[solder_silk_layer] =
1538 Buffer->Data->Layer[component_silk_layer];
1539 Buffer->Data->Layer[component_silk_layer] = swap;
1541 /* swap layer groups when balanced */
1542 sgroup = GetLayerGroupNumberByNumber (solder_silk_layer);
1543 cgroup = GetLayerGroupNumberByNumber (component_silk_layer);
1544 if (PCB->LayerGroups.Number[cgroup] == PCB->LayerGroups.Number[sgroup])
1546 for (j = k = 0; j < PCB->LayerGroups.Number[sgroup]; j++)
1548 int t1, t2;
1549 Cardinal cnumber = PCB->LayerGroups.Entries[cgroup][k];
1550 Cardinal snumber = PCB->LayerGroups.Entries[sgroup][j];
1552 if (snumber >= max_copper_layer)
1553 continue;
1554 swap = Buffer->Data->Layer[snumber];
1556 while (cnumber >= max_copper_layer)
1558 k++;
1559 cnumber = PCB->LayerGroups.Entries[cgroup][k];
1561 Buffer->Data->Layer[snumber] = Buffer->Data->Layer[cnumber];
1562 Buffer->Data->Layer[cnumber] = swap;
1563 k++;
1564 /* move the thermal flags with the layers */
1565 ALLPIN_LOOP (Buffer->Data);
1567 t1 = TEST_THERM (snumber, pin);
1568 t2 = TEST_THERM (cnumber, pin);
1569 ASSIGN_THERM (snumber, t2, pin);
1570 ASSIGN_THERM (cnumber, t1, pin);
1572 ENDALL_LOOP;
1573 VIA_LOOP (Buffer->Data);
1575 t1 = TEST_THERM (snumber, via);
1576 t2 = TEST_THERM (cnumber, via);
1577 ASSIGN_THERM (snumber, t2, via);
1578 ASSIGN_THERM (cnumber, t1, via);
1580 END_LOOP;
1583 SetBufferBoundingBox (Buffer);
1584 SetCrosshairRangeToBuffer ();
1587 /* ----------------------------------------------------------------------
1588 * moves the passed object to the passed buffer and removes it
1589 * from its original place
1591 void *
1592 MoveObjectToBuffer (DataType *Destination, DataType *Src,
1593 int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1595 /* setup local identifiers used by move operations */
1596 Dest = Destination;
1597 Source = Src;
1598 return (ObjectOperation (&MoveBufferFunctions, Type, Ptr1, Ptr2, Ptr3));
1601 /* ----------------------------------------------------------------------
1602 * Adds the passed object to the passed buffer
1604 void *
1605 CopyObjectToBuffer (DataType *Destination, DataType *Src,
1606 int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1608 /* setup local identifiers used by Add operations */
1609 Dest = Destination;
1610 Source = Src;
1611 return (ObjectOperation (&AddBufferFunctions, Type, Ptr1, Ptr2, Ptr3));
1614 /* ---------------------------------------------------------------------- */
1616 HID_Action rotate_action_list[] = {
1617 {"FreeRotateBuffer", 0, ActionFreeRotateBuffer,
1618 freerotatebuffer_syntax, freerotatebuffer_help},
1619 {"LoadFootprint", 0, LoadFootprint,
1620 0,0}
1623 REGISTER_ACTIONS (rotate_action_list)