hid/gtk (GL): I think the polygon renderer works in mask mode now
[geda-pcb/pcjc2.git] / src / buffer.c
blob4f98732e1d3cd8847c6cec60f52b530b5819ac55
1 /*!
2 * \file src/buffer.c
4 * \brief Functions used by paste- and move/copy buffer.
6 * <hr>
8 * <h1><b>Copyright.</b></h1>\n
10 * PCB, interactive printed circuit board design
12 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 * Contact addresses for paper mail and Email:
29 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
30 * Thomas.Nau@rz.uni-ulm.de
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
38 #include <stdlib.h>
39 #include <memory.h>
40 #include <math.h>
42 #include "global.h"
44 #include "buffer.h"
45 #include "copy.h"
46 #include "create.h"
47 #include "crosshair.h"
48 #include "data.h"
49 #include "error.h"
50 #include "mymem.h"
51 #include "mirror.h"
52 #include "misc.h"
53 #include "parse_l.h"
54 #include "polygon.h"
55 #include "rats.h"
56 #include "rotate.h"
57 #include "remove.h"
58 #include "rtree.h"
59 #include "search.h"
60 #include "select.h"
61 #include "set.h"
63 #ifdef HAVE_LIBDMALLOC
64 #include <dmalloc.h>
65 #endif
67 /* ---------------------------------------------------------------------------
68 * some local prototypes
70 static void *AddViaToBuffer (PinType *);
71 static void *AddLineToBuffer (LayerType *, LineType *);
72 static void *AddArcToBuffer (LayerType *, ArcType *);
73 static void *AddRatToBuffer (RatType *);
74 static void *AddTextToBuffer (LayerType *, TextType *);
75 static void *AddPolygonToBuffer (LayerType *, PolygonType *);
76 static void *AddElementToBuffer (ElementType *);
77 static void *MoveViaToBuffer (PinType *);
78 static void *MoveLineToBuffer (LayerType *, LineType *);
79 static void *MoveArcToBuffer (LayerType *, ArcType *);
80 static void *MoveRatToBuffer (RatType *);
81 static void *MoveTextToBuffer (LayerType *, TextType *);
82 static void *MovePolygonToBuffer (LayerType *, PolygonType *);
83 static void *MoveElementToBuffer (ElementType *);
84 static void SwapBuffer (BufferType *);
86 #define ARG(n) (argc > (n) ? argv[n] : 0)
88 /* ---------------------------------------------------------------------------
89 * some local identifiers
91 static DataType *Dest, *Source;
93 static ObjectFunctionType AddBufferFunctions = {
94 AddLineToBuffer,
95 AddTextToBuffer,
96 AddPolygonToBuffer,
97 AddViaToBuffer,
98 AddElementToBuffer,
99 NULL,
100 NULL,
101 NULL,
102 NULL,
103 NULL,
104 AddArcToBuffer,
105 AddRatToBuffer
106 }, MoveBufferFunctions =
109 MoveLineToBuffer,
110 MoveTextToBuffer,
111 MovePolygonToBuffer,
112 MoveViaToBuffer,
113 MoveElementToBuffer,
114 NULL, NULL, NULL, NULL, NULL, MoveArcToBuffer, MoveRatToBuffer};
116 static int ExtraFlag = 0;
119 * \brief Copies a via to paste buffer.
121 static void *
122 AddViaToBuffer (PinType *Via)
124 return (CreateNewVia (Dest, Via->X, Via->Y, Via->Thickness, Via->Clearance,
125 Via->Mask, Via->DrillingHole, Via->Name,
126 MaskFlags (Via->Flags, NOCOPY_FLAGS | ExtraFlag)));
130 * \brief Copies a rat-line to paste buffer.
132 static void *
133 AddRatToBuffer (RatType *Rat)
135 return (CreateNewRat (Dest, Rat->Point1.X, Rat->Point1.Y,
136 Rat->Point2.X, Rat->Point2.Y, Rat->group1,
137 Rat->group2, Rat->Thickness,
138 MaskFlags (Rat->Flags, NOCOPY_FLAGS | ExtraFlag)));
142 * \brief Copies a line to buffer.
144 static void *
145 AddLineToBuffer (LayerType *Layer, LineType *Line)
147 LineType *line;
148 LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
150 line = CreateNewLineOnLayer (layer, Line->Point1.X, Line->Point1.Y,
151 Line->Point2.X, Line->Point2.Y,
152 Line->Thickness, Line->Clearance,
153 MaskFlags (Line->Flags,
154 NOCOPY_FLAGS | ExtraFlag));
155 if (line && Line->Number)
156 line->Number = strdup (Line->Number);
157 return (line);
161 * \brief Copies an arc to buffer.
163 static void *
164 AddArcToBuffer (LayerType *Layer, ArcType *Arc)
166 LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
168 return (CreateNewArcOnLayer (layer, Arc->X, Arc->Y,
169 Arc->Width, Arc->Height, Arc->StartAngle, Arc->Delta,
170 Arc->Thickness, Arc->Clearance,
171 MaskFlags (Arc->Flags,
172 NOCOPY_FLAGS | ExtraFlag)));
176 * \brief Copies a text to buffer.
178 static void *
179 AddTextToBuffer (LayerType *Layer, TextType *Text)
181 LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
183 return (CreateNewText (layer, &PCB->Font, Text->X, Text->Y,
184 Text->Direction, Text->Scale, Text->TextString,
185 MaskFlags (Text->Flags, ExtraFlag)));
189 * \brief Copies a polygon to buffer.
191 static void *
192 AddPolygonToBuffer (LayerType *Layer, PolygonType *Polygon)
194 LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
195 PolygonType *polygon;
197 polygon = CreateNewPolygon (layer, Polygon->Flags);
198 CopyPolygonLowLevel (polygon, Polygon);
200 /* Update the polygon r-tree. Unlike similarly named functions for
201 * other objects, CreateNewPolygon does not do this as it creates a
202 * skeleton polygon object, which won't have correct bounds.
204 if (!layer->polygon_tree)
205 layer->polygon_tree = r_create_tree (NULL, 0, 0);
206 r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
208 CLEAR_FLAG (NOCOPY_FLAGS | ExtraFlag, polygon);
209 return (polygon);
213 * \brief Copies a element to buffer.
215 static void *
216 AddElementToBuffer (ElementType *Element)
218 return CopyElementLowLevel (Dest, Element, false, 0, 0, NOCOPY_FLAGS | ExtraFlag);
222 * \brief Moves a via to paste buffer without allocating memory for the
223 * name.
225 static void *
226 MoveViaToBuffer (PinType *via)
228 RestoreToPolygon (Source, VIA_TYPE, via, via);
230 r_delete_entry (Source->via_tree, (BoxType *) via);
231 Source->Via = g_list_remove (Source->Via, via);
232 Source->ViaN --;
233 Dest->Via = g_list_append (Dest->Via, via);
234 Dest->ViaN ++;
236 CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, via);
238 if (!Dest->via_tree)
239 Dest->via_tree = r_create_tree (NULL, 0, 0);
240 r_insert_entry (Dest->via_tree, (BoxType *)via, 0);
241 ClearFromPolygon (Dest, VIA_TYPE, via, via);
242 return via;
246 * \brief Moves a rat-line to paste buffer.
248 static void *
249 MoveRatToBuffer (RatType *rat)
251 r_delete_entry (Source->rat_tree, (BoxType *)rat);
253 Source->Rat = g_list_remove (Source->Rat, rat);
254 Source->RatN --;
255 Dest->Rat = g_list_append (Dest->Rat, rat);
256 Dest->RatN ++;
258 CLEAR_FLAG (NOCOPY_FLAGS, rat);
260 if (!Dest->rat_tree)
261 Dest->rat_tree = r_create_tree (NULL, 0, 0);
262 r_insert_entry (Dest->rat_tree, (BoxType *)rat, 0);
263 return rat;
267 * \brief Moves a line to buffer.
269 static void *
270 MoveLineToBuffer (LayerType *layer, LineType *line)
272 LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
274 RestoreToPolygon (Source, LINE_TYPE, layer, line);
275 r_delete_entry (layer->line_tree, (BoxType *)line);
277 layer->Line = g_list_remove (layer->Line, line);
278 layer->LineN --;
279 lay->Line = g_list_append (lay->Line, line);
280 lay->LineN ++;
282 CLEAR_FLAG (NOCOPY_FLAGS, line);
284 if (!lay->line_tree)
285 lay->line_tree = r_create_tree (NULL, 0, 0);
286 r_insert_entry (lay->line_tree, (BoxType *)line, 0);
287 ClearFromPolygon (Dest, LINE_TYPE, lay, line);
288 return (line);
292 * \brief Moves an arc to buffer.
294 static void *
295 MoveArcToBuffer (LayerType *layer, ArcType *arc)
297 LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
299 RestoreToPolygon (Source, ARC_TYPE, layer, arc);
300 r_delete_entry (layer->arc_tree, (BoxType *)arc);
302 layer->Arc = g_list_remove (layer->Arc, arc);
303 layer->ArcN --;
304 lay->Arc = g_list_append (lay->Arc, arc);
305 lay->ArcN ++;
307 CLEAR_FLAG (NOCOPY_FLAGS, arc);
309 if (!lay->arc_tree)
310 lay->arc_tree = r_create_tree (NULL, 0, 0);
311 r_insert_entry (lay->arc_tree, (BoxType *)arc, 0);
312 ClearFromPolygon (Dest, ARC_TYPE, lay, arc);
313 return (arc);
317 * \brief Moves a text to buffer without allocating memory for the name.
319 static void *
320 MoveTextToBuffer (LayerType *layer, TextType *text)
322 LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
324 r_delete_entry (layer->text_tree, (BoxType *)text);
325 RestoreToPolygon (Source, TEXT_TYPE, layer, text);
327 layer->Text = g_list_remove (layer->Text, text);
328 layer->TextN --;
329 lay->Text = g_list_append (lay->Text, text);
330 lay->TextN ++;
332 if (!lay->text_tree)
333 lay->text_tree = r_create_tree (NULL, 0, 0);
334 r_insert_entry (lay->text_tree, (BoxType *)text, 0);
335 ClearFromPolygon (Dest, TEXT_TYPE, lay, text);
336 return (text);
340 * \brief Moves a polygon to buffer.
342 * Doesn't allocate memory for the points.
344 static void *
345 MovePolygonToBuffer (LayerType *layer, PolygonType *polygon)
347 LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
349 r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
351 layer->Polygon = g_list_remove (layer->Polygon, polygon);
352 layer->PolygonN --;
353 lay->Polygon = g_list_append (lay->Polygon, polygon);
354 lay->PolygonN ++;
356 CLEAR_FLAG (NOCOPY_FLAGS, polygon);
358 if (!lay->polygon_tree)
359 lay->polygon_tree = r_create_tree (NULL, 0, 0);
360 r_insert_entry (lay->polygon_tree, (BoxType *)polygon, 0);
361 return (polygon);
365 * \brief Moves a element to buffer without allocating memory for
366 * pins/names.
368 static void *
369 MoveElementToBuffer (ElementType *element)
372 * Delete the element from the source (remove it from trees,
373 * restore to polygons)
375 r_delete_element (Source, element);
377 Source->Element = g_list_remove (Source->Element, element);
378 Source->ElementN --;
379 Dest->Element = g_list_append (Dest->Element, element);
380 Dest->ElementN ++;
382 PIN_LOOP (element);
384 RestoreToPolygon(Source, PIN_TYPE, element, pin);
385 CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, pin);
387 END_LOOP;
388 PAD_LOOP (element);
390 RestoreToPolygon(Source, PAD_TYPE, element, pad);
391 CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, pad);
393 END_LOOP;
394 SetElementBoundingBox (Dest, element, &PCB->Font);
396 * Now clear the from the polygons in the destination
398 PIN_LOOP (element);
400 ClearFromPolygon (Dest, PIN_TYPE, element, pin);
402 END_LOOP;
403 PAD_LOOP (element);
405 ClearFromPolygon (Dest, PAD_TYPE, element, pad);
407 END_LOOP;
409 return element;
413 * \brief Calculates the bounding box of the buffer.
415 void
416 SetBufferBoundingBox (BufferType *Buffer)
418 BoxType *box = GetDataBoundingBox (Buffer->Data);
420 if (box)
421 Buffer->BoundingBox = *box;
425 * \brief Clears the contents of the paste buffer.
427 void
428 ClearBuffer (BufferType *Buffer)
430 if (Buffer && Buffer->Data)
432 FreeDataMemory (Buffer->Data);
433 Buffer->Data->pcb = PCB;
438 * \brief Copies all selected and visible objects to the paste buffer.
440 * \return true if any objects have been removed.
442 void
443 AddSelectedToBuffer (BufferType *Buffer, Coord X, Coord Y, bool LeaveSelected)
445 /* switch crosshair off because adding objects to the pastebuffer
446 * may change the 'valid' area for the cursor
448 if (!LeaveSelected)
449 ExtraFlag = SELECTEDFLAG;
450 notify_crosshair_change (false);
451 Source = PCB->Data;
452 Dest = Buffer->Data;
453 SelectedOperation (&AddBufferFunctions, false, ALL_TYPES);
455 /* set origin to passed or current position */
456 if (X || Y)
458 Buffer->X = X;
459 Buffer->Y = Y;
461 else
463 Buffer->X = Crosshair.X;
464 Buffer->Y = Crosshair.Y;
466 notify_crosshair_change (true);
467 ExtraFlag = 0;
471 * \brief Loads element data from file/library into buffer.
473 * Parse the file with disabled 'PCB mode' (see parser).
475 * \return false on error, if successful, update some other stuff and
476 * reposition the pastebuffer.
478 bool
479 LoadElementToBuffer (BufferType *Buffer, char *Name, bool FromFile)
481 ElementType *element;
483 ClearBuffer (Buffer);
484 if (FromFile)
486 if (!ParseElementFile (Buffer->Data, Name))
488 if (Settings.ShowBottomSide)
489 SwapBuffer (Buffer);
490 SetBufferBoundingBox (Buffer);
491 if (Buffer->Data->ElementN)
493 element = Buffer->Data->Element->data;
494 Buffer->X = element->MarkX;
495 Buffer->Y = element->MarkY;
497 else
499 Buffer->X = 0;
500 Buffer->Y = 0;
502 return (true);
505 else
507 if (!ParseLibraryEntry (Buffer->Data, Name)
508 && Buffer->Data->ElementN != 0)
510 element = Buffer->Data->Element->data;
512 /* always add elements using top-side coordinates */
513 if (Settings.ShowBottomSide)
514 MirrorElementCoordinates (Buffer->Data, element, 0);
515 SetElementBoundingBox (Buffer->Data, element, &PCB->Font);
517 /* set buffer offset to 'mark' position */
518 Buffer->X = element->MarkX;
519 Buffer->Y = element->MarkY;
520 SetBufferBoundingBox (Buffer);
521 return (true);
524 /* release memory which might have been acquired */
525 ClearBuffer (Buffer);
526 return (false);
530 typedef struct {
531 char *footprint;
532 int footprint_allocated;
533 int menu_idx;
534 int entry_idx;
535 } FootprintHashEntry;
537 static FootprintHashEntry *footprint_hash = 0;
538 int footprint_hash_size = 0;
540 void
541 clear_footprint_hash ()
543 int i;
544 if (!footprint_hash)
545 return;
546 for (i=0; i<footprint_hash_size; i++)
547 if (footprint_hash[i].footprint_allocated)
548 free (footprint_hash[i].footprint);
549 free (footprint_hash);
550 footprint_hash = NULL;
551 footprint_hash_size = 0;
555 * \brief Used to sort footprint pointer entries.
557 * \note We include the index numbers so that same-named footprints are
558 * sorted by the library search order.
560 static int
561 footprint_hash_cmp (const void *va, const void *vb)
563 int i;
564 FootprintHashEntry *a = (FootprintHashEntry *)va;
565 FootprintHashEntry *b = (FootprintHashEntry *)vb;
567 i = strcmp (a->footprint, b->footprint);
568 if (i == 0)
569 i = a->menu_idx - b->menu_idx;
570 if (i == 0)
571 i = a->entry_idx - b->entry_idx;
572 return i;
575 void
576 make_footprint_hash ()
578 int i, j;
579 char *fp;
580 int num_entries = 0;
582 clear_footprint_hash ();
584 for (i=0; i<Library.MenuN; i++)
585 for (j=0; j<Library.Menu[i].EntryN; j++)
586 num_entries ++;
587 footprint_hash = (FootprintHashEntry *)malloc (num_entries * sizeof(FootprintHashEntry));
588 num_entries = 0;
590 /* There are two types of library entries. The file-based types
591 have a Template of (char *)-1 and the AllocatedMemory is the full
592 path to the footprint file. The m4 ones have the footprint name
593 in brackets in the description. */
594 for (i=0; i<Library.MenuN; i++)
596 #ifdef DEBUG
597 printf("In make_footprint_hash, looking for footprints in %s\n",
598 Library.Menu[i].directory);
599 #endif
601 for (j=0; j<Library.Menu[i].EntryN; j++)
603 footprint_hash[num_entries].menu_idx = i;
604 footprint_hash[num_entries].entry_idx = j;
605 if (Library.Menu[i].Entry[j].Template == (char *) -1)
606 /* file */
608 #ifdef DEBUG
609 /* printf(" ... Examining file %s\n", Library.Menu[i].Entry[j].AllocatedMemory); */
610 #endif
611 fp = strrchr (Library.Menu[i].Entry[j].AllocatedMemory, '/');
613 if (!fp)
614 fp = strrchr (Library.Menu[i].Entry[j].AllocatedMemory, '\\');
616 if (fp)
617 fp ++;
618 else
619 fp = Library.Menu[i].Entry[j].AllocatedMemory;
621 #ifdef DEBUG
622 /* printf(" ... found file footprint %s\n", fp); */
623 #endif
625 footprint_hash[num_entries].footprint = fp;
626 footprint_hash[num_entries].footprint_allocated = 0;
628 else
629 /* m4 */
631 fp = strrchr (Library.Menu[i].Entry[j].Description, '[');
632 if (fp)
634 footprint_hash[num_entries].footprint = strdup (fp+1);
635 footprint_hash[num_entries].footprint_allocated = 1;
636 fp = strchr (footprint_hash[num_entries].footprint, ']');
637 if (fp)
638 *fp = 0;
640 else
642 fp = Library.Menu[i].Entry[j].Description;
643 footprint_hash[num_entries].footprint = fp;
644 footprint_hash[num_entries].footprint_allocated = 0;
647 num_entries ++;
651 footprint_hash_size = num_entries;
652 qsort (footprint_hash, num_entries, sizeof(footprint_hash[0]), footprint_hash_cmp);
654 #ifdef DEBUG
655 printf(" found footprints: \n");
656 for (i=0; i<num_entries; i++)
657 printf("[%s]\n", footprint_hash[i].footprint);
658 #endif
663 * \brief Searches for the given element by "footprint" name, and loads
664 * it into the buffer.
666 * Figuring out which library entry is the one we want is a little
667 * tricky. For file-based footprints, it's just a matter of finding
668 * the first match in the search list. For m4-based footprints you
669 * need to know what magic to pass to the m4 functions. Fortunately,
670 * the footprint needed is determined when we build the m4 libraries
671 * and stored as a comment in the description, so we can search for
672 * that to find the magic we need. We use a hash to store the
673 * corresponding footprints and pointers to the library tree so we can
674 * quickly find the various bits we need to load a given
675 * footprint.
677 FootprintHashEntry *
678 search_footprint_hash (const char *footprint)
680 int i, min, max, c;
682 /* Standard binary search */
684 min = -1;
685 max = footprint_hash_size;
687 while (max - min > 1)
689 i = (min+max)/2;
690 c = strcmp (footprint, footprint_hash[i].footprint);
691 if (c < 0)
692 max = i;
693 else if (c > 0)
694 min = i;
695 else
697 /* We want to return the first match, not just any match. */
698 while (i > 0
699 && strcmp (footprint, footprint_hash[i-1].footprint) == 0)
700 i--;
701 return & footprint_hash[i];
704 return NULL;
708 * \brief .
710 * \return zero on success, non-zero on error.
713 LoadFootprintByName (BufferType *Buffer, char *Footprint)
715 int i;
716 FootprintHashEntry *fpe;
717 LibraryMenuType *menu;
718 LibraryEntryType *entry;
719 char *with_fp = NULL;
721 if (!footprint_hash)
722 make_footprint_hash ();
724 fpe = search_footprint_hash (Footprint);
725 if (!fpe)
727 with_fp = Concat (Footprint, ".fp", NULL);
728 fpe = search_footprint_hash (with_fp);
729 if (fpe)
730 Footprint = with_fp;
732 if (!fpe)
734 Message(_("Unable to load footprint %s\n"), Footprint);
735 return 1;
738 menu = & Library.Menu[fpe->menu_idx];
739 entry = & menu->Entry[fpe->entry_idx];
741 if (entry->Template == (char *) -1)
743 i = LoadElementToBuffer (Buffer, entry->AllocatedMemory, true);
744 if (with_fp)
745 free (with_fp);
746 return i ? 0 : 1;
748 else
750 char *args;
752 args = Concat("'", EMPTY (entry->Template), "' '",
753 EMPTY (entry->Value), "' '", EMPTY (entry->Package), "'", NULL);
754 i = LoadElementToBuffer (Buffer, args, false);
756 free (args);
757 if (with_fp)
758 free (with_fp);
759 return i ? 0 : 1;
762 #ifdef DEBUG
764 int j;
765 printf("Library path: %s\n", Settings.LibraryPath);
766 printf("Library tree: %s\n", Settings.LibraryTree);
768 printf("Library:\n");
769 for (i=0; i<Library.MenuN; i++)
771 printf(" [%02d] Name: %s\n", i, Library.Menu[i].Name);
772 printf(" Dir: %s\n", Library.Menu[i].directory);
773 printf(" Sty: %s\n", Library.Menu[i].Style);
774 for (j=0; j<Library.Menu[i].EntryN; j++)
776 printf(" [%02d] E: %s\n", j, Library.Menu[i].Entry[j].ListEntry);
777 if (Library.Menu[i].Entry[j].Template == (char *) -1)
778 printf(" A: %s\n", Library.Menu[i].Entry[j].AllocatedMemory);
779 else
781 printf(" T: %s\n", Library.Menu[i].Entry[j].Template);
782 printf(" P: %s\n", Library.Menu[i].Entry[j].Package);
783 printf(" V: %s\n", Library.Menu[i].Entry[j].Value);
784 printf(" D: %s\n", Library.Menu[i].Entry[j].Description);
786 if (j == 10)
787 break;
791 #endif
795 static const char loadfootprint_syntax[] =
796 N_("LoadFootprint(filename[,refdes,value])");
798 static const char loadfootprint_help[] =
799 N_("Loads a single footprint by name.");
801 /* %start-doc actions LoadFootprint
803 Loads a single footprint by name, rather than by reference or through
804 the library. If a refdes and value are specified, those are inserted
805 into the footprint as well. The footprint remains in the paste buffer.
807 %end-doc */
810 * \brief This action is called from ActionElementAddIf().
813 LoadFootprint (int argc, char **argv, Coord x, Coord y)
815 char *name = ARG(0);
816 char *refdes = ARG(1);
817 char *value = ARG(2);
818 ElementType *e;
820 if (!name)
821 AFAIL (loadfootprint);
823 if (LoadFootprintByName (PASTEBUFFER, name))
824 return 1;
826 if (PASTEBUFFER->Data->ElementN == 0)
828 Message(_("Footprint %s contains no elements"), name);
829 return 1;
831 if (PASTEBUFFER->Data->ElementN > 1)
833 Message(_("Footprint %s contains multiple elements"), name);
834 return 1;
837 e = PASTEBUFFER->Data->Element->data;
839 if (e->Name[0].TextString)
840 free (e->Name[0].TextString);
841 e->Name[0].TextString = strdup (name);
843 if (e->Name[1].TextString)
844 free (e->Name[1].TextString);
845 e->Name[1].TextString = refdes ? strdup (refdes) : 0;
847 if (e->Name[2].TextString)
848 free (e->Name[2].TextString);
849 e->Name[2].TextString = value ? strdup (value) : 0;
851 return 0;
855 * \brief Break buffer element into pieces.
857 bool
858 SmashBufferElement (BufferType *Buffer)
860 ElementType *element;
861 Cardinal group;
862 LayerType *top_layer, *bottom_layer;
864 if (Buffer->Data->ElementN != 1)
866 Message (_("Error! Buffer doesn't contain a single element\n"));
867 return (false);
870 * At this point the buffer should contain just a single element.
871 * Now we detach the single element from the buffer and then clear the
872 * buffer, ready to receive the smashed elements. As a result of detaching
873 * it the single element is orphaned from the buffer and thus will not be
874 * free()'d by FreeDataMemory (called via ClearBuffer). This leaves it
875 * around for us to smash bits off it. It then becomes our responsibility,
876 * however, to free the single element when we're finished with it.
878 element = Buffer->Data->Element->data;
879 Buffer->Data->Element = NULL;
880 Buffer->Data->ElementN = 0;
881 ClearBuffer (Buffer);
882 ELEMENTLINE_LOOP (element);
884 CreateNewLineOnLayer (&Buffer->Data->SILKLAYER,
885 line->Point1.X, line->Point1.Y,
886 line->Point2.X, line->Point2.Y,
887 line->Thickness, 0, NoFlags ());
888 if (line)
889 line->Number = STRDUP (NAMEONPCB_NAME (element));
891 END_LOOP;
892 ARC_LOOP (element);
894 CreateNewArcOnLayer (&Buffer->Data->SILKLAYER,
895 arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle,
896 arc->Delta, arc->Thickness, 0, NoFlags ());
898 END_LOOP;
899 PIN_LOOP (element);
901 FlagType f = NoFlags ();
902 AddFlags (f, VIAFLAG);
903 if (TEST_FLAG (HOLEFLAG, pin))
904 AddFlags (f, HOLEFLAG);
906 CreateNewVia (Buffer->Data, pin->X, pin->Y,
907 pin->Thickness, pin->Clearance, pin->Mask,
908 pin->DrillingHole, pin->Number, f);
910 END_LOOP;
911 group = GetLayerGroupNumberBySide (SWAP_IDENT ? BOTTOM_SIDE : TOP_SIDE);
912 top_layer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
913 group = GetLayerGroupNumberBySide (SWAP_IDENT ? TOP_SIDE : BOTTOM_SIDE);
914 bottom_layer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
915 PAD_LOOP (element);
917 LineType *line;
918 line = CreateNewLineOnLayer (TEST_FLAG (ONSOLDERFLAG, pad) ? bottom_layer : top_layer,
919 pad->Point1.X, pad->Point1.Y,
920 pad->Point2.X, pad->Point2.Y,
921 pad->Thickness, pad->Clearance, NoFlags ());
922 if (line)
923 line->Number = STRDUP (pad->Number);
925 END_LOOP;
926 FreeElementMemory (element);
927 g_slice_free (ElementType, element);
928 return (true);
932 * \brief See if a polygon is a rectangle.
934 * If so, canonicalize it.
937 static int
938 polygon_is_rectangle (PolygonType *poly)
940 int i, best;
941 PointType temp[4];
942 if (poly->PointN != 4 || poly->HoleIndexN != 0)
943 return 0;
944 best = 0;
945 for (i=1; i<4; i++)
946 if (poly->Points[i].X < poly->Points[best].X
947 || poly->Points[i].Y < poly->Points[best].Y)
948 best = i;
949 for (i=0; i<4; i++)
950 temp[i] = poly->Points[(i+best)%4];
951 if (temp[0].X == temp[1].X)
952 memcpy (poly->Points, temp, sizeof(temp));
953 else
955 /* reverse them */
956 poly->Points[0] = temp[0];
957 poly->Points[1] = temp[3];
958 poly->Points[2] = temp[2];
959 poly->Points[3] = temp[1];
961 if (poly->Points[0].X == poly->Points[1].X
962 && poly->Points[1].Y == poly->Points[2].Y
963 && poly->Points[2].X == poly->Points[3].X
964 && poly->Points[3].Y == poly->Points[0].Y)
965 return 1;
966 return 0;
970 * \brief Convert buffer contents into an element.
972 bool
973 ConvertBufferToElement (BufferType *Buffer)
975 ElementType *Element;
976 Cardinal group;
977 Cardinal pin_n = 1;
978 bool hasParts = false, crooked = false;
979 int onsolder;
980 bool warned = false;
982 if (Buffer->Data->pcb == 0)
983 Buffer->Data->pcb = PCB;
985 Element = CreateNewElement (PCB->Data, &PCB->Font, NoFlags (),
986 NULL, NULL, NULL, PASTEBUFFER->X,
987 PASTEBUFFER->Y, 0, 100,
988 MakeFlags (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG),
989 false);
990 if (!Element)
991 return (false);
992 VIA_LOOP (Buffer->Data);
994 char num[8];
995 if (via->Mask < via->Thickness)
996 via->Mask = via->Thickness + 2 * MASKFRAME;
997 if (via->Name)
998 CreateNewPin (Element, via->X, via->Y, via->Thickness,
999 via->Clearance, via->Mask, via->DrillingHole,
1000 NULL, via->Name, MaskFlags (via->Flags,
1001 VIAFLAG | NOCOPY_FLAGS |
1002 SELECTEDFLAG | WARNFLAG));
1003 else
1005 sprintf (num, "%d", pin_n++);
1006 CreateNewPin (Element, via->X, via->Y, via->Thickness,
1007 via->Clearance, via->Mask, via->DrillingHole,
1008 NULL, num, MaskFlags (via->Flags,
1009 VIAFLAG | NOCOPY_FLAGS | SELECTEDFLAG
1010 | WARNFLAG));
1012 hasParts = true;
1014 END_LOOP;
1016 for (onsolder = 0; onsolder < 2; onsolder ++)
1018 int side;
1019 int onsolderflag;
1021 if ((!onsolder) == (!SWAP_IDENT))
1023 side = TOP_SIDE;
1024 onsolderflag = NOFLAG;
1026 else
1028 side = BOTTOM_SIDE;
1029 onsolderflag = ONSOLDERFLAG;
1032 #define MAYBE_WARN() \
1033 if (onsolder && !hasParts && !warned) \
1035 warned = true; \
1036 Message \
1037 (_("Warning: All of the pads are on the opposite\n" \
1038 "side from the component - that's probably not what\n" \
1039 "you wanted\n")); \
1042 /* get the component-side SM pads */
1043 group = GetLayerGroupNumberBySide (side);
1044 GROUP_LOOP (Buffer->Data, group);
1046 char num[8];
1047 LINE_LOOP (layer);
1049 sprintf (num, "%d", pin_n++);
1050 CreateNewPad (Element, line->Point1.X,
1051 line->Point1.Y, line->Point2.X,
1052 line->Point2.Y, line->Thickness,
1053 line->Clearance,
1054 line->Thickness + line->Clearance, NULL,
1055 line->Number ? line->Number : num,
1056 MakeFlags (onsolderflag));
1057 MAYBE_WARN();
1058 hasParts = true;
1060 END_LOOP;
1061 POLYGON_LOOP (layer);
1063 Coord x1, y1, x2, y2, w, h, t;
1065 if (! polygon_is_rectangle (polygon))
1067 crooked = true;
1068 continue;
1071 w = polygon->Points[2].X - polygon->Points[0].X;
1072 h = polygon->Points[1].Y - polygon->Points[0].Y;
1073 t = (w < h) ? w : h;
1074 x1 = polygon->Points[0].X + t/2;
1075 y1 = polygon->Points[0].Y + t/2;
1076 x2 = x1 + (w-t);
1077 y2 = y1 + (h-t);
1079 sprintf (num, "%d", pin_n++);
1080 CreateNewPad (Element,
1081 x1, y1, x2, y2, t,
1082 2 * Settings.Keepaway,
1083 t + Settings.Keepaway,
1084 NULL, num,
1085 MakeFlags (SQUAREFLAG | onsolderflag));
1086 MAYBE_WARN();
1087 hasParts = true;
1089 END_LOOP;
1091 END_LOOP;
1094 /* now add the silkscreen. NOTE: elements must have pads or pins too */
1095 LINE_LOOP (&Buffer->Data->SILKLAYER);
1097 if (line->Number && !NAMEONPCB_NAME (Element))
1098 NAMEONPCB_NAME (Element) = strdup (line->Number);
1099 CreateNewLineInElement (Element, line->Point1.X,
1100 line->Point1.Y, line->Point2.X,
1101 line->Point2.Y, line->Thickness);
1102 hasParts = true;
1104 END_LOOP;
1105 ARC_LOOP (&Buffer->Data->SILKLAYER);
1107 CreateNewArcInElement (Element, arc->X, arc->Y, arc->Width,
1108 arc->Height, arc->StartAngle, arc->Delta,
1109 arc->Thickness);
1110 hasParts = true;
1112 END_LOOP;
1113 if (!hasParts)
1115 DestroyObject (PCB->Data, ELEMENT_TYPE, Element, Element, Element);
1116 Message (_("There was nothing to convert!\n"
1117 "Elements must have some silk, pads or pins.\n"));
1118 return (false);
1120 if (crooked)
1121 Message (_("There were polygons that can't be made into pins!\n"
1122 "So they were not included in the element\n"));
1123 Element->MarkX = Buffer->X;
1124 Element->MarkY = Buffer->Y;
1125 if (SWAP_IDENT)
1126 SET_FLAG (ONSOLDERFLAG, Element);
1127 SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
1128 ClearBuffer (Buffer);
1129 MoveObjectToBuffer (Buffer->Data, PCB->Data, ELEMENT_TYPE, Element, Element,
1130 Element);
1131 SetBufferBoundingBox (Buffer);
1132 return (true);
1136 * \brief Load PCB into buffer.
1138 * Parse the file with enabled 'PCB mode' (see parser).
1139 * If successful, update some other stuff.
1141 bool
1142 LoadLayoutToBuffer (BufferType *Buffer, char *Filename)
1144 PCBType *newPCB = CreateNewPCB ();
1146 /* new data isn't added to the undo list */
1147 if (!ParsePCB (newPCB, Filename))
1149 /* clear data area and replace pointer */
1150 ClearBuffer (Buffer);
1151 free (Buffer->Data);
1152 Buffer->Data = newPCB->Data;
1153 newPCB->Data = NULL;
1154 Buffer->X = newPCB->CursorX;
1155 Buffer->Y = newPCB->CursorY;
1156 RemovePCB (newPCB);
1157 Buffer->Data->pcb = PCB;
1158 return (true);
1161 /* release unused memory */
1162 RemovePCB (newPCB);
1163 Buffer->Data->pcb = PCB;
1164 return (false);
1168 * \brief Rotates the contents of the pastebuffer.
1170 void
1171 RotateBuffer (BufferType *Buffer, BYTE Number)
1173 /* rotate vias */
1174 VIA_LOOP (Buffer->Data);
1176 r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
1177 ROTATE_VIA_LOWLEVEL (via, Buffer->X, Buffer->Y, Number);
1178 SetPinBoundingBox (via);
1179 r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
1181 END_LOOP;
1183 /* elements */
1184 ELEMENT_LOOP (Buffer->Data);
1186 RotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
1187 Number);
1189 END_LOOP;
1191 /* all layer related objects */
1192 ALLLINE_LOOP (Buffer->Data);
1194 r_delete_entry (layer->line_tree, (BoxType *)line);
1195 RotateLineLowLevel (line, Buffer->X, Buffer->Y, Number);
1196 r_insert_entry (layer->line_tree, (BoxType *)line, 0);
1198 ENDALL_LOOP;
1199 ALLARC_LOOP (Buffer->Data);
1201 r_delete_entry (layer->arc_tree, (BoxType *)arc);
1202 RotateArcLowLevel (arc, Buffer->X, Buffer->Y, Number);
1203 r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
1205 ENDALL_LOOP;
1206 ALLTEXT_LOOP (Buffer->Data);
1208 r_delete_entry (layer->text_tree, (BoxType *)text);
1209 RotateTextLowLevel (text, Buffer->X, Buffer->Y, Number);
1210 r_insert_entry (layer->text_tree, (BoxType *)text, 0);
1212 ENDALL_LOOP;
1213 ALLPOLYGON_LOOP (Buffer->Data);
1215 r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
1216 RotatePolygonLowLevel (polygon, Buffer->X, Buffer->Y, Number);
1217 r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
1219 ENDALL_LOOP;
1221 /* finally the origin and the bounding box */
1222 ROTATE (Buffer->X, Buffer->Y, Buffer->X, Buffer->Y, Number);
1223 RotateBoxLowLevel (&Buffer->BoundingBox, Buffer->X, Buffer->Y, Number);
1224 SetCrosshairRangeToBuffer ();
1227 static void
1228 free_rotate (Coord *x, Coord *y, Coord cx, Coord cy, double cosa, double sina)
1230 double nx, ny;
1231 Coord px = *x - cx;
1232 Coord py = *y - cy;
1234 nx = px * cosa + py * sina;
1235 ny = py * cosa - px * sina;
1237 *x = nx + cx;
1238 *y = ny + cy;
1241 void
1242 FreeRotateElementLowLevel (DataType *Data, ElementType *Element,
1243 Coord X, Coord Y,
1244 double cosa, double sina, Angle angle)
1246 /* solder side objects need a different orientation */
1248 /* the text subroutine decides by itself if the direction
1249 * is to be corrected
1251 #if 0
1252 ELEMENTTEXT_LOOP (Element);
1254 if (Data && Data->name_tree[n])
1255 r_delete_entry (Data->name_tree[n], (BoxType *)text);
1256 RotateTextLowLevel (text, X, Y, Number);
1258 END_LOOP;
1259 #endif
1260 ELEMENTLINE_LOOP (Element);
1262 free_rotate (&line->Point1.X, &line->Point1.Y, X, Y, cosa, sina);
1263 free_rotate (&line->Point2.X, &line->Point2.Y, X, Y, cosa, sina);
1264 SetLineBoundingBox (line);
1266 END_LOOP;
1267 PIN_LOOP (Element);
1269 /* pre-delete the pins from the pin-tree before their coordinates change */
1270 if (Data)
1271 r_delete_entry (Data->pin_tree, (BoxType *)pin);
1272 RestoreToPolygon (Data, PIN_TYPE, Element, pin);
1273 free_rotate (&pin->X, &pin->Y, X, Y, cosa, sina);
1274 SetPinBoundingBox (pin);
1276 END_LOOP;
1277 PAD_LOOP (Element);
1279 /* pre-delete the pads before their coordinates change */
1280 if (Data)
1281 r_delete_entry (Data->pad_tree, (BoxType *)pad);
1282 RestoreToPolygon (Data, PAD_TYPE, Element, pad);
1283 free_rotate (&pad->Point1.X, &pad->Point1.Y, X, Y, cosa, sina);
1284 free_rotate (&pad->Point2.X, &pad->Point2.Y, X, Y, cosa, sina);
1285 SetLineBoundingBox ((LineType *) pad);
1287 END_LOOP;
1288 ARC_LOOP (Element);
1290 free_rotate (&arc->X, &arc->Y, X, Y, cosa, sina);
1291 arc->StartAngle = NormalizeAngle (arc->StartAngle + angle);
1293 END_LOOP;
1295 free_rotate (&Element->MarkX, &Element->MarkY, X, Y, cosa, sina);
1296 SetElementBoundingBox (Data, Element, &PCB->Font);
1297 ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element);
1300 void
1301 FreeRotateBuffer (BufferType *Buffer, Angle angle)
1303 double cosa, sina;
1305 cosa = cos(angle * M_PI/180.0);
1306 sina = sin(angle * M_PI/180.0);
1308 /* rotate vias */
1309 VIA_LOOP (Buffer->Data);
1311 r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
1312 free_rotate (&via->X, &via->Y, Buffer->X, Buffer->Y, cosa, sina);
1313 SetPinBoundingBox (via);
1314 r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
1316 END_LOOP;
1318 /* elements */
1319 ELEMENT_LOOP (Buffer->Data);
1321 FreeRotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
1322 cosa, sina, angle);
1324 END_LOOP;
1326 /* all layer related objects */
1327 ALLLINE_LOOP (Buffer->Data);
1329 r_delete_entry (layer->line_tree, (BoxType *)line);
1330 free_rotate (&line->Point1.X, &line->Point1.Y, Buffer->X, Buffer->Y, cosa, sina);
1331 free_rotate (&line->Point2.X, &line->Point2.Y, Buffer->X, Buffer->Y, cosa, sina);
1332 SetLineBoundingBox (line);
1333 r_insert_entry (layer->line_tree, (BoxType *)line, 0);
1335 ENDALL_LOOP;
1336 ALLARC_LOOP (Buffer->Data);
1338 r_delete_entry (layer->arc_tree, (BoxType *)arc);
1339 free_rotate (&arc->X, &arc->Y, Buffer->X, Buffer->Y, cosa, sina);
1340 arc->StartAngle = NormalizeAngle (arc->StartAngle + angle);
1341 r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
1343 ENDALL_LOOP;
1344 /* FIXME: rotate text */
1345 ALLPOLYGON_LOOP (Buffer->Data);
1347 r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
1348 POLYGONPOINT_LOOP (polygon);
1350 free_rotate (&point->X, &point->Y, Buffer->X, Buffer->Y, cosa, sina);
1352 END_LOOP;
1353 SetPolygonBoundingBox (polygon);
1354 r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
1356 ENDALL_LOOP;
1358 SetBufferBoundingBox (Buffer);
1359 SetCrosshairRangeToBuffer ();
1363 /* -------------------------------------------------------------------------- */
1365 static const char freerotatebuffer_syntax[] =
1366 N_("FreeRotateBuffer([Angle])");
1368 static const char freerotatebuffer_help[] =
1369 N_("Rotates the current paste buffer contents by the specified angle. The\n"
1370 "angle is given in degrees. If no angle is given, the user is prompted\n"
1371 "for one.\n");
1373 /* %start-doc actions FreeRotateBuffer
1375 Rotates the contents of the pastebuffer by an arbitrary angle. If no
1376 angle is given, the user is prompted for one.
1378 %end-doc */
1381 ActionFreeRotateBuffer(int argc, char **argv, Coord x, Coord y)
1383 char *angle_s;
1385 if (argc < 1)
1386 angle_s = gui->prompt_for (_("Enter Rotation (degrees, CCW):"), "0");
1387 else
1388 angle_s = argv[0];
1390 notify_crosshair_change (false);
1391 FreeRotateBuffer(PASTEBUFFER, strtod(angle_s, 0));
1392 notify_crosshair_change (true);
1393 return 0;
1397 * \brief Initializes the buffers by allocating memory.
1399 void
1400 InitBuffers (void)
1402 int i;
1404 for (i = 0; i < MAX_BUFFER; i++)
1405 Buffers[i].Data = CreateNewBuffer ();
1408 void
1409 SwapBuffers (void)
1411 int i;
1413 for (i = 0; i < MAX_BUFFER; i++)
1414 SwapBuffer (&Buffers[i]);
1415 SetCrosshairRangeToBuffer ();
1418 void
1419 MirrorBuffer (BufferType *Buffer)
1421 int i;
1423 if (Buffer->Data->ElementN)
1425 Message (_("You can't mirror a buffer that has elements!\n"));
1426 return;
1428 for (i = 0; i < max_copper_layer + EXTRA_LAYERS; i++)
1430 LayerType *layer = Buffer->Data->Layer + i;
1431 if (layer->TextN)
1433 Message (_("You can't mirror a buffer that has text!\n"));
1434 return;
1437 /* set buffer offset to 'mark' position */
1438 Buffer->X = SWAP_X (Buffer->X);
1439 Buffer->Y = SWAP_Y (Buffer->Y);
1440 VIA_LOOP (Buffer->Data);
1442 via->X = SWAP_X (via->X);
1443 via->Y = SWAP_Y (via->Y);
1445 END_LOOP;
1446 ALLLINE_LOOP (Buffer->Data);
1448 line->Point1.X = SWAP_X (line->Point1.X);
1449 line->Point1.Y = SWAP_Y (line->Point1.Y);
1450 line->Point2.X = SWAP_X (line->Point2.X);
1451 line->Point2.Y = SWAP_Y (line->Point2.Y);
1453 ENDALL_LOOP;
1454 ALLARC_LOOP (Buffer->Data);
1456 arc->X = SWAP_X (arc->X);
1457 arc->Y = SWAP_Y (arc->Y);
1458 arc->StartAngle = SWAP_ANGLE (arc->StartAngle);
1459 arc->Delta = SWAP_DELTA (arc->Delta);
1460 SetArcBoundingBox (arc);
1462 ENDALL_LOOP;
1463 ALLPOLYGON_LOOP (Buffer->Data);
1465 POLYGONPOINT_LOOP (polygon);
1467 point->X = SWAP_X (point->X);
1468 point->Y = SWAP_Y (point->Y);
1470 END_LOOP;
1471 SetPolygonBoundingBox (polygon);
1473 ENDALL_LOOP;
1474 SetBufferBoundingBox (Buffer);
1475 SetCrosshairRangeToBuffer ();
1480 * \brief Flip components/tracks from one side to the other.
1482 static void
1483 SwapBuffer (BufferType *Buffer)
1485 int j, k;
1486 Cardinal top_group, bottom_group;
1487 LayerType swap;
1489 ELEMENT_LOOP (Buffer->Data);
1491 r_delete_element (Buffer->Data, element);
1492 MirrorElementCoordinates (Buffer->Data, element, 0);
1494 END_LOOP;
1495 /* set buffer offset to 'mark' position */
1496 Buffer->X = SWAP_X (Buffer->X);
1497 Buffer->Y = SWAP_Y (Buffer->Y);
1498 VIA_LOOP (Buffer->Data);
1500 r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
1501 via->X = SWAP_X (via->X);
1502 via->Y = SWAP_Y (via->Y);
1503 SetPinBoundingBox (via);
1504 r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
1506 END_LOOP;
1507 ALLLINE_LOOP (Buffer->Data);
1509 r_delete_entry (layer->line_tree, (BoxType *)line);
1510 line->Point1.X = SWAP_X (line->Point1.X);
1511 line->Point1.Y = SWAP_Y (line->Point1.Y);
1512 line->Point2.X = SWAP_X (line->Point2.X);
1513 line->Point2.Y = SWAP_Y (line->Point2.Y);
1514 SetLineBoundingBox (line);
1515 r_insert_entry (layer->line_tree, (BoxType *)line, 0);
1517 ENDALL_LOOP;
1518 ALLARC_LOOP (Buffer->Data);
1520 r_delete_entry (layer->arc_tree, (BoxType *)arc);
1521 arc->X = SWAP_X (arc->X);
1522 arc->Y = SWAP_Y (arc->Y);
1523 arc->StartAngle = SWAP_ANGLE (arc->StartAngle);
1524 arc->Delta = SWAP_DELTA (arc->Delta);
1525 SetArcBoundingBox (arc);
1526 r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
1528 ENDALL_LOOP;
1529 ALLPOLYGON_LOOP (Buffer->Data);
1531 r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
1532 POLYGONPOINT_LOOP (polygon);
1534 point->X = SWAP_X (point->X);
1535 point->Y = SWAP_Y (point->Y);
1537 END_LOOP;
1538 SetPolygonBoundingBox (polygon);
1539 r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
1540 /* hmmm, how to handle clip */
1542 ENDALL_LOOP;
1543 ALLTEXT_LOOP (Buffer->Data);
1545 r_delete_entry (layer->text_tree, (BoxType *)text);
1546 text->X = SWAP_X (text->X);
1547 text->Y = SWAP_Y (text->Y);
1548 TOGGLE_FLAG (ONSOLDERFLAG, text);
1549 SetTextBoundingBox (&PCB->Font, text);
1550 r_insert_entry (layer->text_tree, (BoxType *)text, 0);
1552 ENDALL_LOOP;
1553 /* swap silkscreen layers */
1554 swap = Buffer->Data->Layer[bottom_silk_layer];
1555 Buffer->Data->Layer[bottom_silk_layer] =
1556 Buffer->Data->Layer[top_silk_layer];
1557 Buffer->Data->Layer[top_silk_layer] = swap;
1559 /* swap layer groups when balanced */
1560 top_group = GetLayerGroupNumberBySide (TOP_SIDE);
1561 bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
1562 if (PCB->LayerGroups.Number[top_group] == PCB->LayerGroups.Number[bottom_group])
1564 for (j = k = 0; j < PCB->LayerGroups.Number[bottom_group]; j++)
1566 int t1, t2;
1567 Cardinal top_number = PCB->LayerGroups.Entries[top_group][k];
1568 Cardinal bottom_number = PCB->LayerGroups.Entries[bottom_group][j];
1570 if (bottom_number >= max_copper_layer)
1571 continue;
1572 swap = Buffer->Data->Layer[bottom_number];
1574 while (top_number >= max_copper_layer)
1576 k++;
1577 top_number = PCB->LayerGroups.Entries[top_group][k];
1579 Buffer->Data->Layer[bottom_number] = Buffer->Data->Layer[top_number];
1580 Buffer->Data->Layer[top_number] = swap;
1581 k++;
1582 /* move the thermal flags with the layers */
1583 ALLPIN_LOOP (Buffer->Data);
1585 t1 = TEST_THERM (bottom_number, pin);
1586 t2 = TEST_THERM (top_number, pin);
1587 ASSIGN_THERM (bottom_number, t2, pin);
1588 ASSIGN_THERM (top_number, t1, pin);
1590 ENDALL_LOOP;
1591 VIA_LOOP (Buffer->Data);
1593 t1 = TEST_THERM (bottom_number, via);
1594 t2 = TEST_THERM (top_number, via);
1595 ASSIGN_THERM (bottom_number, t2, via);
1596 ASSIGN_THERM (top_number, t1, via);
1598 END_LOOP;
1601 SetBufferBoundingBox (Buffer);
1602 SetCrosshairRangeToBuffer ();
1606 * \brief Moves the passed object to the passed buffer and removes it
1607 * from its original place.
1609 void *
1610 MoveObjectToBuffer (DataType *Destination, DataType *Src,
1611 int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1613 /* setup local identifiers used by move operations */
1614 Dest = Destination;
1615 Source = Src;
1616 return (ObjectOperation (&MoveBufferFunctions, Type, Ptr1, Ptr2, Ptr3));
1620 * \brief Adds the passed object to the passed buffer.
1622 void *
1623 CopyObjectToBuffer (DataType *Destination, DataType *Src,
1624 int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1626 /* setup local identifiers used by Add operations */
1627 Dest = Destination;
1628 Source = Src;
1629 return (ObjectOperation (&AddBufferFunctions, Type, Ptr1, Ptr2, Ptr3));
1632 /* ---------------------------------------------------------------------- */
1634 HID_Action rotate_action_list[] = {
1635 {"FreeRotateBuffer", 0, ActionFreeRotateBuffer,
1636 freerotatebuffer_syntax, freerotatebuffer_help},
1637 {"LoadFootprint", 0, LoadFootprint,
1638 0,0}
1641 REGISTER_ACTIONS (rotate_action_list)