(no commit message)
[geda-pcb/pcjc2.git] / src / buffer.c
blob7067b8d002654242864c4925bc2d583cf4ed37df
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, NOCOPY_FLAGS | 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, NOCOPY_FLAGS | 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 NOCOPY_FLAGS | 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 NOCOPY_FLAGS | 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 (NOCOPY_FLAGS | ExtraFlag, polygon);
205 return (polygon);
208 /* ---------------------------------------------------------------------------
209 * copies a element to buffer
211 static void *
212 AddElementToBuffer (ElementType *Element)
214 return CopyElementLowLevel (Dest, Element, false, 0, 0, NOCOPY_FLAGS | 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 | NOCOPY_FLAGS, 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 (NOCOPY_FLAGS, 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 (NOCOPY_FLAGS, 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 (NOCOPY_FLAGS, 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 (NOCOPY_FLAGS, 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 | NOCOPY_FLAGS, pin);
379 END_LOOP;
380 PAD_LOOP (element);
382 RestoreToPolygon(Source, PAD_TYPE, element, pad);
383 CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, 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.ShowBottomSide)
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.ShowBottomSide)
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[] =
779 N_("LoadFootprint(filename[,refdes,value])");
781 static const char loadfootprint_help[] =
782 N_("Loads a single footprint by name.");
784 /* %start-doc actions LoadFootprint
786 Loads a single footprint by name, rather than by reference or through
787 the library. If a refdes and value are specified, those are inserted
788 into the footprint as well. The footprint remains in the paste buffer.
790 %end-doc */
793 LoadFootprint (int argc, char **argv, Coord x, Coord y)
795 char *name = ARG(0);
796 char *refdes = ARG(1);
797 char *value = ARG(2);
798 ElementType *e;
800 if (!name)
801 AFAIL (loadfootprint);
803 if (LoadFootprintByName (PASTEBUFFER, name))
804 return 1;
806 if (PASTEBUFFER->Data->ElementN == 0)
808 Message(_("Footprint %s contains no elements"), name);
809 return 1;
811 if (PASTEBUFFER->Data->ElementN > 1)
813 Message(_("Footprint %s contains multiple elements"), name);
814 return 1;
817 e = PASTEBUFFER->Data->Element->data;
819 if (e->Name[0].TextString)
820 free (e->Name[0].TextString);
821 e->Name[0].TextString = strdup (name);
823 if (e->Name[1].TextString)
824 free (e->Name[1].TextString);
825 e->Name[1].TextString = refdes ? strdup (refdes) : 0;
827 if (e->Name[2].TextString)
828 free (e->Name[2].TextString);
829 e->Name[2].TextString = value ? strdup (value) : 0;
831 return 0;
834 /*---------------------------------------------------------------------------
836 * break buffer element into pieces
838 bool
839 SmashBufferElement (BufferType *Buffer)
841 ElementType *element;
842 Cardinal group;
843 LayerType *top_layer, *bottom_layer;
845 if (Buffer->Data->ElementN != 1)
847 Message (_("Error! Buffer doesn't contain a single element\n"));
848 return (false);
851 * At this point the buffer should contain just a single element.
852 * Now we detach the single element from the buffer and then clear the
853 * buffer, ready to receive the smashed elements. As a result of detaching
854 * it the single element is orphaned from the buffer and thus will not be
855 * free()'d by FreeDataMemory (called via ClearBuffer). This leaves it
856 * around for us to smash bits off it. It then becomes our responsibility,
857 * however, to free the single element when we're finished with it.
859 element = Buffer->Data->Element->data;
860 Buffer->Data->Element = NULL;
861 Buffer->Data->ElementN = 0;
862 ClearBuffer (Buffer);
863 ELEMENTLINE_LOOP (element);
865 CreateNewLineOnLayer (&Buffer->Data->SILKLAYER,
866 line->Point1.X, line->Point1.Y,
867 line->Point2.X, line->Point2.Y,
868 line->Thickness, 0, NoFlags ());
869 if (line)
870 line->Number = STRDUP (NAMEONPCB_NAME (element));
872 END_LOOP;
873 ARC_LOOP (element);
875 CreateNewArcOnLayer (&Buffer->Data->SILKLAYER,
876 arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle,
877 arc->Delta, arc->Thickness, 0, NoFlags ());
879 END_LOOP;
880 PIN_LOOP (element);
882 FlagType f = NoFlags ();
883 AddFlags (f, VIAFLAG);
884 if (TEST_FLAG (HOLEFLAG, pin))
885 AddFlags (f, HOLEFLAG);
887 CreateNewVia (Buffer->Data, pin->X, pin->Y,
888 pin->Thickness, pin->Clearance, pin->Mask,
889 pin->DrillingHole, pin->Number, f);
891 END_LOOP;
892 group = GetLayerGroupNumberBySide (SWAP_IDENT ? BOTTOM_SIDE : TOP_SIDE);
893 top_layer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
894 group = GetLayerGroupNumberBySide (SWAP_IDENT ? TOP_SIDE : BOTTOM_SIDE);
895 bottom_layer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
896 PAD_LOOP (element);
898 LineType *line;
899 line = CreateNewLineOnLayer (TEST_FLAG (ONSOLDERFLAG, pad) ? bottom_layer : top_layer,
900 pad->Point1.X, pad->Point1.Y,
901 pad->Point2.X, pad->Point2.Y,
902 pad->Thickness, pad->Clearance, NoFlags ());
903 if (line)
904 line->Number = STRDUP (pad->Number);
906 END_LOOP;
907 FreeElementMemory (element);
908 g_slice_free (ElementType, element);
909 return (true);
912 /*---------------------------------------------------------------------------
914 * see if a polygon is a rectangle. If so, canonicalize it.
917 static int
918 polygon_is_rectangle (PolygonType *poly)
920 int i, best;
921 PointType temp[4];
922 if (poly->PointN != 4 || poly->HoleIndexN != 0)
923 return 0;
924 best = 0;
925 for (i=1; i<4; i++)
926 if (poly->Points[i].X < poly->Points[best].X
927 || poly->Points[i].Y < poly->Points[best].Y)
928 best = i;
929 for (i=0; i<4; i++)
930 temp[i] = poly->Points[(i+best)%4];
931 if (temp[0].X == temp[1].X)
932 memcpy (poly->Points, temp, sizeof(temp));
933 else
935 /* reverse them */
936 poly->Points[0] = temp[0];
937 poly->Points[1] = temp[3];
938 poly->Points[2] = temp[2];
939 poly->Points[3] = temp[1];
941 if (poly->Points[0].X == poly->Points[1].X
942 && poly->Points[1].Y == poly->Points[2].Y
943 && poly->Points[2].X == poly->Points[3].X
944 && poly->Points[3].Y == poly->Points[0].Y)
945 return 1;
946 return 0;
949 /*---------------------------------------------------------------------------
951 * convert buffer contents into an element
953 bool
954 ConvertBufferToElement (BufferType *Buffer)
956 ElementType *Element;
957 Cardinal group;
958 Cardinal pin_n = 1;
959 bool hasParts = false, crooked = false;
960 int onsolder;
961 bool warned = false;
963 if (Buffer->Data->pcb == 0)
964 Buffer->Data->pcb = PCB;
966 Element = CreateNewElement (PCB->Data, &PCB->Font, NoFlags (),
967 NULL, NULL, NULL, PASTEBUFFER->X,
968 PASTEBUFFER->Y, 0, 100,
969 MakeFlags (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG),
970 false);
971 if (!Element)
972 return (false);
973 VIA_LOOP (Buffer->Data);
975 char num[8];
976 if (via->Mask < via->Thickness)
977 via->Mask = via->Thickness + 2 * MASKFRAME;
978 if (via->Name)
979 CreateNewPin (Element, via->X, via->Y, via->Thickness,
980 via->Clearance, via->Mask, via->DrillingHole,
981 NULL, via->Name, MaskFlags (via->Flags,
982 VIAFLAG | NOCOPY_FLAGS |
983 SELECTEDFLAG | WARNFLAG));
984 else
986 sprintf (num, "%d", pin_n++);
987 CreateNewPin (Element, via->X, via->Y, via->Thickness,
988 via->Clearance, via->Mask, via->DrillingHole,
989 NULL, num, MaskFlags (via->Flags,
990 VIAFLAG | NOCOPY_FLAGS | SELECTEDFLAG
991 | WARNFLAG));
993 hasParts = true;
995 END_LOOP;
997 for (onsolder = 0; onsolder < 2; onsolder ++)
999 int side;
1000 int onsolderflag;
1002 if ((!onsolder) == (!SWAP_IDENT))
1004 side = TOP_SIDE;
1005 onsolderflag = NOFLAG;
1007 else
1009 side = BOTTOM_SIDE;
1010 onsolderflag = ONSOLDERFLAG;
1013 #define MAYBE_WARN() \
1014 if (onsolder && !hasParts && !warned) \
1016 warned = true; \
1017 Message \
1018 (_("Warning: All of the pads are on the opposite\n" \
1019 "side from the component - that's probably not what\n" \
1020 "you wanted\n")); \
1023 /* get the component-side SM pads */
1024 group = GetLayerGroupNumberBySide (side);
1025 GROUP_LOOP (Buffer->Data, group);
1027 char num[8];
1028 LINE_LOOP (layer);
1030 sprintf (num, "%d", pin_n++);
1031 CreateNewPad (Element, line->Point1.X,
1032 line->Point1.Y, line->Point2.X,
1033 line->Point2.Y, line->Thickness,
1034 line->Clearance,
1035 line->Thickness + line->Clearance, NULL,
1036 line->Number ? line->Number : num,
1037 MakeFlags (onsolderflag));
1038 MAYBE_WARN();
1039 hasParts = true;
1041 END_LOOP;
1042 POLYGON_LOOP (layer);
1044 Coord x1, y1, x2, y2, w, h, t;
1046 if (! polygon_is_rectangle (polygon))
1048 crooked = true;
1049 continue;
1052 w = polygon->Points[2].X - polygon->Points[0].X;
1053 h = polygon->Points[1].Y - polygon->Points[0].Y;
1054 t = (w < h) ? w : h;
1055 x1 = polygon->Points[0].X + t/2;
1056 y1 = polygon->Points[0].Y + t/2;
1057 x2 = x1 + (w-t);
1058 y2 = y1 + (h-t);
1060 sprintf (num, "%d", pin_n++);
1061 CreateNewPad (Element,
1062 x1, y1, x2, y2, t,
1063 2 * Settings.Keepaway,
1064 t + Settings.Keepaway,
1065 NULL, num,
1066 MakeFlags (SQUAREFLAG | onsolderflag));
1067 MAYBE_WARN();
1068 hasParts = true;
1070 END_LOOP;
1072 END_LOOP;
1075 /* now add the silkscreen. NOTE: elements must have pads or pins too */
1076 LINE_LOOP (&Buffer->Data->SILKLAYER);
1078 if (line->Number && !NAMEONPCB_NAME (Element))
1079 NAMEONPCB_NAME (Element) = strdup (line->Number);
1080 CreateNewLineInElement (Element, line->Point1.X,
1081 line->Point1.Y, line->Point2.X,
1082 line->Point2.Y, line->Thickness);
1083 hasParts = true;
1085 END_LOOP;
1086 ARC_LOOP (&Buffer->Data->SILKLAYER);
1088 CreateNewArcInElement (Element, arc->X, arc->Y, arc->Width,
1089 arc->Height, arc->StartAngle, arc->Delta,
1090 arc->Thickness);
1091 hasParts = true;
1093 END_LOOP;
1094 if (!hasParts)
1096 DestroyObject (PCB->Data, ELEMENT_TYPE, Element, Element, Element);
1097 Message (_("There was nothing to convert!\n"
1098 "Elements must have some silk, pads or pins.\n"));
1099 return (false);
1101 if (crooked)
1102 Message (_("There were polygons that can't be made into pins!\n"
1103 "So they were not included in the element\n"));
1104 Element->MarkX = Buffer->X;
1105 Element->MarkY = Buffer->Y;
1106 if (SWAP_IDENT)
1107 SET_FLAG (ONSOLDERFLAG, Element);
1108 SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
1109 ClearBuffer (Buffer);
1110 MoveObjectToBuffer (Buffer->Data, PCB->Data, ELEMENT_TYPE, Element, Element,
1111 Element);
1112 SetBufferBoundingBox (Buffer);
1113 return (true);
1116 /* ---------------------------------------------------------------------------
1117 * load PCB into buffer
1118 * parse the file with enabled 'PCB mode' (see parser)
1119 * if successful, update some other stuff
1121 bool
1122 LoadLayoutToBuffer (BufferType *Buffer, char *Filename)
1124 PCBType *newPCB = CreateNewPCB (false);
1126 /* new data isn't added to the undo list */
1127 if (!ParsePCB (newPCB, Filename))
1129 /* clear data area and replace pointer */
1130 ClearBuffer (Buffer);
1131 free (Buffer->Data);
1132 Buffer->Data = newPCB->Data;
1133 newPCB->Data = NULL;
1134 Buffer->X = newPCB->CursorX;
1135 Buffer->Y = newPCB->CursorY;
1136 RemovePCB (newPCB);
1137 Buffer->Data->pcb = PCB;
1138 return (true);
1141 /* release unused memory */
1142 RemovePCB (newPCB);
1143 Buffer->Data->pcb = PCB;
1144 return (false);
1147 /* ---------------------------------------------------------------------------
1148 * rotates the contents of the pastebuffer
1150 void
1151 RotateBuffer (BufferType *Buffer, BYTE Number)
1153 /* rotate vias */
1154 VIA_LOOP (Buffer->Data);
1156 r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
1157 ROTATE_VIA_LOWLEVEL (via, Buffer->X, Buffer->Y, Number);
1158 SetPinBoundingBox (via);
1159 r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
1161 END_LOOP;
1163 /* elements */
1164 ELEMENT_LOOP (Buffer->Data);
1166 RotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
1167 Number);
1169 END_LOOP;
1171 /* all layer related objects */
1172 ALLLINE_LOOP (Buffer->Data);
1174 r_delete_entry (layer->line_tree, (BoxType *)line);
1175 RotateLineLowLevel (line, Buffer->X, Buffer->Y, Number);
1176 r_insert_entry (layer->line_tree, (BoxType *)line, 0);
1178 ENDALL_LOOP;
1179 ALLARC_LOOP (Buffer->Data);
1181 r_delete_entry (layer->arc_tree, (BoxType *)arc);
1182 RotateArcLowLevel (arc, Buffer->X, Buffer->Y, Number);
1183 r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
1185 ENDALL_LOOP;
1186 ALLTEXT_LOOP (Buffer->Data);
1188 r_delete_entry (layer->text_tree, (BoxType *)text);
1189 RotateTextLowLevel (text, Buffer->X, Buffer->Y, Number);
1190 r_insert_entry (layer->text_tree, (BoxType *)text, 0);
1192 ENDALL_LOOP;
1193 ALLPOLYGON_LOOP (Buffer->Data);
1195 r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
1196 RotatePolygonLowLevel (polygon, Buffer->X, Buffer->Y, Number);
1197 r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
1199 ENDALL_LOOP;
1201 /* finally the origin and the bounding box */
1202 ROTATE (Buffer->X, Buffer->Y, Buffer->X, Buffer->Y, Number);
1203 RotateBoxLowLevel (&Buffer->BoundingBox, Buffer->X, Buffer->Y, Number);
1204 SetCrosshairRangeToBuffer ();
1207 static void
1208 free_rotate (Coord *x, Coord *y, Coord cx, Coord cy, double cosa, double sina)
1210 double nx, ny;
1211 Coord px = *x - cx;
1212 Coord py = *y - cy;
1214 nx = px * cosa + py * sina;
1215 ny = py * cosa - px * sina;
1217 *x = nx + cx;
1218 *y = ny + cy;
1221 void
1222 FreeRotateElementLowLevel (DataType *Data, ElementType *Element,
1223 Coord X, Coord Y,
1224 double cosa, double sina, Angle angle)
1226 /* solder side objects need a different orientation */
1228 /* the text subroutine decides by itself if the direction
1229 * is to be corrected
1231 #if 0
1232 ELEMENTTEXT_LOOP (Element);
1234 if (Data && Data->name_tree[n])
1235 r_delete_entry (Data->name_tree[n], (BoxType *)text);
1236 RotateTextLowLevel (text, X, Y, Number);
1238 END_LOOP;
1239 #endif
1240 ELEMENTLINE_LOOP (Element);
1242 free_rotate (&line->Point1.X, &line->Point1.Y, X, Y, cosa, sina);
1243 free_rotate (&line->Point2.X, &line->Point2.Y, X, Y, cosa, sina);
1244 SetLineBoundingBox (line);
1246 END_LOOP;
1247 PIN_LOOP (Element);
1249 /* pre-delete the pins from the pin-tree before their coordinates change */
1250 if (Data)
1251 r_delete_entry (Data->pin_tree, (BoxType *)pin);
1252 RestoreToPolygon (Data, PIN_TYPE, Element, pin);
1253 free_rotate (&pin->X, &pin->Y, X, Y, cosa, sina);
1254 SetPinBoundingBox (pin);
1256 END_LOOP;
1257 PAD_LOOP (Element);
1259 /* pre-delete the pads before their coordinates change */
1260 if (Data)
1261 r_delete_entry (Data->pad_tree, (BoxType *)pad);
1262 RestoreToPolygon (Data, PAD_TYPE, Element, pad);
1263 free_rotate (&pad->Point1.X, &pad->Point1.Y, X, Y, cosa, sina);
1264 free_rotate (&pad->Point2.X, &pad->Point2.Y, X, Y, cosa, sina);
1265 SetLineBoundingBox ((LineType *) pad);
1267 END_LOOP;
1268 ARC_LOOP (Element);
1270 free_rotate (&arc->X, &arc->Y, X, Y, cosa, sina);
1271 arc->StartAngle = NormalizeAngle (arc->StartAngle + angle);
1273 END_LOOP;
1275 free_rotate (&Element->MarkX, &Element->MarkY, X, Y, cosa, sina);
1276 SetElementBoundingBox (Data, Element, &PCB->Font);
1277 ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element);
1280 void
1281 FreeRotateBuffer (BufferType *Buffer, Angle angle)
1283 double cosa, sina;
1285 cosa = cos(angle * M_PI/180.0);
1286 sina = sin(angle * M_PI/180.0);
1288 /* rotate vias */
1289 VIA_LOOP (Buffer->Data);
1291 r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
1292 free_rotate (&via->X, &via->Y, Buffer->X, Buffer->Y, cosa, sina);
1293 SetPinBoundingBox (via);
1294 r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
1296 END_LOOP;
1298 /* elements */
1299 ELEMENT_LOOP (Buffer->Data);
1301 FreeRotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
1302 cosa, sina, angle);
1304 END_LOOP;
1306 /* all layer related objects */
1307 ALLLINE_LOOP (Buffer->Data);
1309 r_delete_entry (layer->line_tree, (BoxType *)line);
1310 free_rotate (&line->Point1.X, &line->Point1.Y, Buffer->X, Buffer->Y, cosa, sina);
1311 free_rotate (&line->Point2.X, &line->Point2.Y, Buffer->X, Buffer->Y, cosa, sina);
1312 SetLineBoundingBox (line);
1313 r_insert_entry (layer->line_tree, (BoxType *)line, 0);
1315 ENDALL_LOOP;
1316 ALLARC_LOOP (Buffer->Data);
1318 r_delete_entry (layer->arc_tree, (BoxType *)arc);
1319 free_rotate (&arc->X, &arc->Y, Buffer->X, Buffer->Y, cosa, sina);
1320 arc->StartAngle = NormalizeAngle (arc->StartAngle + angle);
1321 r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
1323 ENDALL_LOOP;
1324 /* FIXME: rotate text */
1325 ALLPOLYGON_LOOP (Buffer->Data);
1327 r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
1328 POLYGONPOINT_LOOP (polygon);
1330 free_rotate (&point->X, &point->Y, Buffer->X, Buffer->Y, cosa, sina);
1332 END_LOOP;
1333 SetPolygonBoundingBox (polygon);
1334 r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
1336 ENDALL_LOOP;
1338 SetBufferBoundingBox (Buffer);
1339 SetCrosshairRangeToBuffer ();
1343 /* -------------------------------------------------------------------------- */
1345 static const char freerotatebuffer_syntax[] =
1346 N_("FreeRotateBuffer([Angle])");
1348 static const char freerotatebuffer_help[] =
1349 N_("Rotates the current paste buffer contents by the specified angle. The\n"
1350 "angle is given in degrees. If no angle is given, the user is prompted\n"
1351 "for one.\n");
1353 /* %start-doc actions FreeRotateBuffer
1355 Rotates the contents of the pastebuffer by an arbitrary angle. If no
1356 angle is given, the user is prompted for one.
1358 %end-doc */
1361 ActionFreeRotateBuffer(int argc, char **argv, Coord x, Coord y)
1363 char *angle_s;
1365 if (argc < 1)
1366 angle_s = gui->prompt_for (_("Enter Rotation (degrees, CCW):"), "0");
1367 else
1368 angle_s = argv[0];
1370 notify_crosshair_change (false);
1371 FreeRotateBuffer(PASTEBUFFER, strtod(angle_s, 0));
1372 notify_crosshair_change (true);
1373 return 0;
1376 /* ---------------------------------------------------------------------------
1377 * initializes the buffers by allocating memory
1379 void
1380 InitBuffers (void)
1382 int i;
1384 for (i = 0; i < MAX_BUFFER; i++)
1385 Buffers[i].Data = CreateNewBuffer ();
1388 void
1389 SwapBuffers (void)
1391 int i;
1393 for (i = 0; i < MAX_BUFFER; i++)
1394 SwapBuffer (&Buffers[i]);
1395 SetCrosshairRangeToBuffer ();
1398 void
1399 MirrorBuffer (BufferType *Buffer)
1401 int i;
1403 if (Buffer->Data->ElementN)
1405 Message (_("You can't mirror a buffer that has elements!\n"));
1406 return;
1408 for (i = 0; i < max_copper_layer + 2; i++)
1410 LayerType *layer = Buffer->Data->Layer + i;
1411 if (layer->TextN)
1413 Message (_("You can't mirror a buffer that has text!\n"));
1414 return;
1417 /* set buffer offset to 'mark' position */
1418 Buffer->X = SWAP_X (Buffer->X);
1419 Buffer->Y = SWAP_Y (Buffer->Y);
1420 VIA_LOOP (Buffer->Data);
1422 via->X = SWAP_X (via->X);
1423 via->Y = SWAP_Y (via->Y);
1425 END_LOOP;
1426 ALLLINE_LOOP (Buffer->Data);
1428 line->Point1.X = SWAP_X (line->Point1.X);
1429 line->Point1.Y = SWAP_Y (line->Point1.Y);
1430 line->Point2.X = SWAP_X (line->Point2.X);
1431 line->Point2.Y = SWAP_Y (line->Point2.Y);
1433 ENDALL_LOOP;
1434 ALLARC_LOOP (Buffer->Data);
1436 arc->X = SWAP_X (arc->X);
1437 arc->Y = SWAP_Y (arc->Y);
1438 arc->StartAngle = SWAP_ANGLE (arc->StartAngle);
1439 arc->Delta = SWAP_DELTA (arc->Delta);
1440 SetArcBoundingBox (arc);
1442 ENDALL_LOOP;
1443 ALLPOLYGON_LOOP (Buffer->Data);
1445 POLYGONPOINT_LOOP (polygon);
1447 point->X = SWAP_X (point->X);
1448 point->Y = SWAP_Y (point->Y);
1450 END_LOOP;
1451 SetPolygonBoundingBox (polygon);
1453 ENDALL_LOOP;
1454 SetBufferBoundingBox (Buffer);
1455 SetCrosshairRangeToBuffer ();
1459 /* ---------------------------------------------------------------------------
1460 * flip components/tracks from one side to the other
1462 static void
1463 SwapBuffer (BufferType *Buffer)
1465 int j, k;
1466 Cardinal top_group, bottom_group;
1467 LayerType swap;
1469 ELEMENT_LOOP (Buffer->Data);
1471 r_delete_element (Buffer->Data, element);
1472 MirrorElementCoordinates (Buffer->Data, element, 0);
1474 END_LOOP;
1475 /* set buffer offset to 'mark' position */
1476 Buffer->X = SWAP_X (Buffer->X);
1477 Buffer->Y = SWAP_Y (Buffer->Y);
1478 VIA_LOOP (Buffer->Data);
1480 r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
1481 via->X = SWAP_X (via->X);
1482 via->Y = SWAP_Y (via->Y);
1483 SetPinBoundingBox (via);
1484 r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
1486 END_LOOP;
1487 ALLLINE_LOOP (Buffer->Data);
1489 r_delete_entry (layer->line_tree, (BoxType *)line);
1490 line->Point1.X = SWAP_X (line->Point1.X);
1491 line->Point1.Y = SWAP_Y (line->Point1.Y);
1492 line->Point2.X = SWAP_X (line->Point2.X);
1493 line->Point2.Y = SWAP_Y (line->Point2.Y);
1494 SetLineBoundingBox (line);
1495 r_insert_entry (layer->line_tree, (BoxType *)line, 0);
1497 ENDALL_LOOP;
1498 ALLARC_LOOP (Buffer->Data);
1500 r_delete_entry (layer->arc_tree, (BoxType *)arc);
1501 arc->X = SWAP_X (arc->X);
1502 arc->Y = SWAP_Y (arc->Y);
1503 arc->StartAngle = SWAP_ANGLE (arc->StartAngle);
1504 arc->Delta = SWAP_DELTA (arc->Delta);
1505 SetArcBoundingBox (arc);
1506 r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
1508 ENDALL_LOOP;
1509 ALLPOLYGON_LOOP (Buffer->Data);
1511 r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
1512 POLYGONPOINT_LOOP (polygon);
1514 point->X = SWAP_X (point->X);
1515 point->Y = SWAP_Y (point->Y);
1517 END_LOOP;
1518 SetPolygonBoundingBox (polygon);
1519 r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
1520 /* hmmm, how to handle clip */
1522 ENDALL_LOOP;
1523 ALLTEXT_LOOP (Buffer->Data);
1525 r_delete_entry (layer->text_tree, (BoxType *)text);
1526 text->X = SWAP_X (text->X);
1527 text->Y = SWAP_Y (text->Y);
1528 TOGGLE_FLAG (ONSOLDERFLAG, text);
1529 SetTextBoundingBox (&PCB->Font, text);
1530 r_insert_entry (layer->text_tree, (BoxType *)text, 0);
1532 ENDALL_LOOP;
1533 /* swap silkscreen layers */
1534 swap = Buffer->Data->Layer[bottom_silk_layer];
1535 Buffer->Data->Layer[bottom_silk_layer] =
1536 Buffer->Data->Layer[top_silk_layer];
1537 Buffer->Data->Layer[top_silk_layer] = swap;
1539 /* swap layer groups when balanced */
1540 top_group = GetLayerGroupNumberBySide (TOP_SIDE);
1541 bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
1542 if (PCB->LayerGroups.Number[top_group] == PCB->LayerGroups.Number[bottom_group])
1544 for (j = k = 0; j < PCB->LayerGroups.Number[bottom_group]; j++)
1546 int t1, t2;
1547 Cardinal top_number = PCB->LayerGroups.Entries[top_group][k];
1548 Cardinal bottom_number = PCB->LayerGroups.Entries[bottom_group][j];
1550 if (bottom_number >= max_copper_layer)
1551 continue;
1552 swap = Buffer->Data->Layer[bottom_number];
1554 while (top_number >= max_copper_layer)
1556 k++;
1557 top_number = PCB->LayerGroups.Entries[top_group][k];
1559 Buffer->Data->Layer[bottom_number] = Buffer->Data->Layer[top_number];
1560 Buffer->Data->Layer[top_number] = swap;
1561 k++;
1562 /* move the thermal flags with the layers */
1563 ALLPIN_LOOP (Buffer->Data);
1565 t1 = TEST_THERM (bottom_number, pin);
1566 t2 = TEST_THERM (top_number, pin);
1567 ASSIGN_THERM (bottom_number, t2, pin);
1568 ASSIGN_THERM (top_number, t1, pin);
1570 ENDALL_LOOP;
1571 VIA_LOOP (Buffer->Data);
1573 t1 = TEST_THERM (bottom_number, via);
1574 t2 = TEST_THERM (top_number, via);
1575 ASSIGN_THERM (bottom_number, t2, via);
1576 ASSIGN_THERM (top_number, t1, via);
1578 END_LOOP;
1581 SetBufferBoundingBox (Buffer);
1582 SetCrosshairRangeToBuffer ();
1585 /* ----------------------------------------------------------------------
1586 * moves the passed object to the passed buffer and removes it
1587 * from its original place
1589 void *
1590 MoveObjectToBuffer (DataType *Destination, DataType *Src,
1591 int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1593 /* setup local identifiers used by move operations */
1594 Dest = Destination;
1595 Source = Src;
1596 return (ObjectOperation (&MoveBufferFunctions, Type, Ptr1, Ptr2, Ptr3));
1599 /* ----------------------------------------------------------------------
1600 * Adds the passed object to the passed buffer
1602 void *
1603 CopyObjectToBuffer (DataType *Destination, DataType *Src,
1604 int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1606 /* setup local identifiers used by Add operations */
1607 Dest = Destination;
1608 Source = Src;
1609 return (ObjectOperation (&AddBufferFunctions, Type, Ptr1, Ptr2, Ptr3));
1612 /* ---------------------------------------------------------------------- */
1614 HID_Action rotate_action_list[] = {
1615 {"FreeRotateBuffer", 0, ActionFreeRotateBuffer,
1616 freerotatebuffer_syntax, freerotatebuffer_help},
1617 {"LoadFootprint", 0, LoadFootprint,
1618 0,0}
1621 REGISTER_ACTIONS (rotate_action_list)