1 /*!
2  * \file src/buffer.c
3  *
4  * \brief Functions used by paste- and move/copy buffer.
5  *
6  * <hr>
7  *
8  * <h1><b>Copyright.</b></h1>\n
9  *
10  * PCB, interactive printed circuit board design
11  *
12  * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
13  *
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.
18  *
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.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program; if not, write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27  *
28  * Contact addresses for paper mail and Email:
29  * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
30  * Thomas.Nau@rz.uni-ulm.de
31  *
32  */
33 
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37 
38 #include <stdlib.h>
39 #include <memory.h>
40 #include <math.h>
41 
42 #include "global.h"
43 
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 "flags.h"
51 #include "mymem.h"
52 #include "mirror.h"
53 #include "misc.h"
54 #include "parse_l.h"
55 #include "polygon.h"
56 #include "rats.h"
57 #include "rotate.h"
58 #include "remove.h"
59 #include "rtree.h"
60 #include "search.h"
61 #include "select.h"
62 #include "set.h"
63 
64 #ifdef HAVE_LIBDMALLOC
65 #include <dmalloc.h>
66 #endif
67 
68 /* ---------------------------------------------------------------------------
69  * some local prototypes
70  */
71 static void *AddViaToBuffer (PinType *);
72 static void *AddLineToBuffer (LayerType *, LineType *);
73 static void *AddArcToBuffer (LayerType *, ArcType *);
74 static void *AddRatToBuffer (RatType *);
75 static void *AddTextToBuffer (LayerType *, TextType *);
76 static void *AddPolygonToBuffer (LayerType *, PolygonType *);
77 static void *AddElementToBuffer (ElementType *);
78 static void *MoveViaToBuffer (PinType *);
79 static void *MoveLineToBuffer (LayerType *, LineType *);
80 static void *MoveArcToBuffer (LayerType *, ArcType *);
81 static void *MoveRatToBuffer (RatType *);
82 static void *MoveTextToBuffer (LayerType *, TextType *);
83 static void *MovePolygonToBuffer (LayerType *, PolygonType *);
84 static void *MoveElementToBuffer (ElementType *);
85 static void SwapBuffer (BufferType *);
86 
87 /* ---------------------------------------------------------------------------
88  * some local identifiers
89  */
90 static DataType *Dest, *Source;
91 
92 static ObjectFunctionType AddBufferFunctions = {
93   AddLineToBuffer,
94   AddTextToBuffer,
95   AddPolygonToBuffer,
96   AddViaToBuffer,
97   AddElementToBuffer,
98   NULL,
99   NULL,
100   NULL,
101   NULL,
102   NULL,
103   AddArcToBuffer,
104   AddRatToBuffer
105 }, MoveBufferFunctions =
106 
107 {
108 MoveLineToBuffer,
109     MoveTextToBuffer,
110     MovePolygonToBuffer,
111     MoveViaToBuffer,
112     MoveElementToBuffer,
113     NULL, NULL, NULL, NULL, NULL, MoveArcToBuffer, MoveRatToBuffer};
114 
115 static int ExtraFlag = 0;
116 
117 /*!
118  * \brief Copies a via to paste buffer.
119  */
120 static void *
AddViaToBuffer(PinType * Via)121 AddViaToBuffer (PinType *Via)
122 {
123   return (CreateNewViaEx (Dest, Via->X, Via->Y, Via->Thickness, Via->Clearance,
124 			Via->Mask, Via->DrillingHole, Via->Name,
125 			MaskFlags (Via->Flags, NOCOPY_FLAGS | ExtraFlag), Via->BuriedFrom, Via->BuriedTo));
126 }
127 
128 /*!
129  * \brief Copies a rat-line to paste buffer.
130  */
131 static void *
AddRatToBuffer(RatType * Rat)132 AddRatToBuffer (RatType *Rat)
133 {
134   return (CreateNewRat (Dest, Rat->Point1.X, Rat->Point1.Y,
135 			Rat->Point2.X, Rat->Point2.Y, Rat->group1,
136 			Rat->group2, Rat->Thickness,
137 			MaskFlags (Rat->Flags, NOCOPY_FLAGS | ExtraFlag)));
138 }
139 
140 /*!
141  * \brief Copies a line to buffer.
142  */
143 static void *
AddLineToBuffer(LayerType * Layer,LineType * Line)144 AddLineToBuffer (LayerType *Layer, LineType *Line)
145 {
146   LineType *line;
147   LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
148 
149   line = CreateNewLineOnLayer (layer, Line->Point1.X, Line->Point1.Y,
150 			       Line->Point2.X, Line->Point2.Y,
151 			       Line->Thickness, Line->Clearance,
152 			       MaskFlags (Line->Flags,
153 					  NOCOPY_FLAGS | ExtraFlag));
154   if (line && Line->Number)
155     line->Number = strdup (Line->Number);
156   return (line);
157 }
158 
159 /*!
160  * \brief Copies an arc to buffer.
161  */
162 static void *
AddArcToBuffer(LayerType * Layer,ArcType * Arc)163 AddArcToBuffer (LayerType *Layer, ArcType *Arc)
164 {
165   LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
166 
167   return (CreateNewArcOnLayer (layer, Arc->X, Arc->Y,
168 			       Arc->Width, Arc->Height, Arc->StartAngle, Arc->Delta,
169 			       Arc->Thickness, Arc->Clearance,
170 			       MaskFlags (Arc->Flags,
171 					  NOCOPY_FLAGS | ExtraFlag)));
172 }
173 
174 /*!
175  * \brief Copies a text to buffer.
176  */
177 static void *
AddTextToBuffer(LayerType * Layer,TextType * Text)178 AddTextToBuffer (LayerType *Layer, TextType *Text)
179 {
180   LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
181 
182   return (CreateNewText (layer, &PCB->Font, Text->X, Text->Y,
183 			 Text->Direction, Text->Scale, Text->TextString,
184 			 MaskFlags (Text->Flags, ExtraFlag)));
185 }
186 
187 /*!
188  * \brief Copies a polygon to buffer.
189  */
190 static void *
AddPolygonToBuffer(LayerType * Layer,PolygonType * Polygon)191 AddPolygonToBuffer (LayerType *Layer, PolygonType *Polygon)
192 {
193   LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
194   PolygonType *polygon;
195 
196   polygon = CreateNewPolygon (layer, Polygon->Flags);
197   CopyPolygonLowLevel (polygon, Polygon);
198 
199   /* Update the polygon r-tree. Unlike similarly named functions for
200    * other objects, CreateNewPolygon does not do this as it creates a
201    * skeleton polygon object, which won't have correct bounds.
202    */
203   if (!layer->polygon_tree)
204     layer->polygon_tree = r_create_tree (NULL, 0, 0);
205   r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
206 
207   CLEAR_FLAG (NOCOPY_FLAGS | ExtraFlag, polygon);
208   return (polygon);
209 }
210 
211 /*!
212  * \brief Copies a element to buffer.
213  */
214 static void *
AddElementToBuffer(ElementType * Element)215 AddElementToBuffer (ElementType *Element)
216 {
217   return CopyElementLowLevel (Dest, Element, false, 0, 0, NOCOPY_FLAGS | ExtraFlag);
218 }
219 
220 /*!
221  * \brief Moves a via to paste buffer without allocating memory for the
222  * name.
223  */
224 static void *
MoveViaToBuffer(PinType * via)225 MoveViaToBuffer (PinType *via)
226 {
227   RestoreToPolygon (Source, VIA_TYPE, via, via);
228 
229   r_delete_entry (Source->via_tree, (BoxType *) via);
230   Source->Via = g_list_remove (Source->Via, via);
231   Source->ViaN --;
232   Dest->Via = g_list_append (Dest->Via, via);
233   Dest->ViaN ++;
234 
235   CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, via);
236 
237   if (!Dest->via_tree)
238     Dest->via_tree = r_create_tree (NULL, 0, 0);
239   r_insert_entry (Dest->via_tree, (BoxType *)via, 0);
240   ClearFromPolygon (Dest, VIA_TYPE, via, via);
241   return via;
242 }
243 
244 /*!
245  * \brief Moves a rat-line to paste buffer.
246  */
247 static void *
MoveRatToBuffer(RatType * rat)248 MoveRatToBuffer (RatType *rat)
249 {
250   r_delete_entry (Source->rat_tree, (BoxType *)rat);
251 
252   Source->Rat = g_list_remove (Source->Rat, rat);
253   Source->RatN --;
254   Dest->Rat = g_list_append (Dest->Rat, rat);
255   Dest->RatN ++;
256 
257   CLEAR_FLAG (NOCOPY_FLAGS, rat);
258 
259   if (!Dest->rat_tree)
260     Dest->rat_tree = r_create_tree (NULL, 0, 0);
261   r_insert_entry (Dest->rat_tree, (BoxType *)rat, 0);
262   return rat;
263 }
264 
265 /*!
266  * \brief Moves a line to buffer.
267  */
268 static void *
MoveLineToBuffer(LayerType * layer,LineType * line)269 MoveLineToBuffer (LayerType *layer, LineType *line)
270 {
271   LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
272 
273   RestoreToPolygon (Source, LINE_TYPE, layer, line);
274   r_delete_entry (layer->line_tree, (BoxType *)line);
275 
276   layer->Line = g_list_remove (layer->Line, line);
277   layer->LineN --;
278   lay->Line = g_list_append (lay->Line, line);
279   lay->LineN ++;
280 
281   CLEAR_FLAG (NOCOPY_FLAGS, line);
282 
283   if (!lay->line_tree)
284     lay->line_tree = r_create_tree (NULL, 0, 0);
285   r_insert_entry (lay->line_tree, (BoxType *)line, 0);
286   ClearFromPolygon (Dest, LINE_TYPE, lay, line);
287   return (line);
288 }
289 
290 /*!
291  * \brief Moves an arc to buffer.
292  */
293 static void *
MoveArcToBuffer(LayerType * layer,ArcType * arc)294 MoveArcToBuffer (LayerType *layer, ArcType *arc)
295 {
296   LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
297 
298   RestoreToPolygon (Source, ARC_TYPE, layer, arc);
299   r_delete_entry (layer->arc_tree, (BoxType *)arc);
300 
301   layer->Arc = g_list_remove (layer->Arc, arc);
302   layer->ArcN --;
303   lay->Arc = g_list_append (lay->Arc, arc);
304   lay->ArcN ++;
305 
306   CLEAR_FLAG (NOCOPY_FLAGS, arc);
307 
308   if (!lay->arc_tree)
309     lay->arc_tree = r_create_tree (NULL, 0, 0);
310   r_insert_entry (lay->arc_tree, (BoxType *)arc, 0);
311   ClearFromPolygon (Dest, ARC_TYPE, lay, arc);
312   return (arc);
313 }
314 
315 /*!
316  * \brief Moves a text to buffer without allocating memory for the name.
317  */
318 static void *
MoveTextToBuffer(LayerType * layer,TextType * text)319 MoveTextToBuffer (LayerType *layer, TextType *text)
320 {
321   LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
322 
323   r_delete_entry (layer->text_tree, (BoxType *)text);
324   RestoreToPolygon (Source, TEXT_TYPE, layer, text);
325 
326   layer->Text = g_list_remove (layer->Text, text);
327   layer->TextN --;
328   lay->Text = g_list_append (lay->Text, text);
329   lay->TextN ++;
330 
331   if (!lay->text_tree)
332     lay->text_tree = r_create_tree (NULL, 0, 0);
333   r_insert_entry (lay->text_tree, (BoxType *)text, 0);
334   ClearFromPolygon (Dest, TEXT_TYPE, lay, text);
335   return (text);
336 }
337 
338 /*!
339  * \brief Moves a polygon to buffer.
340  *
341  * Doesn't allocate memory for the points.
342  */
343 static void *
MovePolygonToBuffer(LayerType * layer,PolygonType * polygon)344 MovePolygonToBuffer (LayerType *layer, PolygonType *polygon)
345 {
346   LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
347 
348   r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
349 
350   layer->Polygon = g_list_remove (layer->Polygon, polygon);
351   layer->PolygonN --;
352   lay->Polygon = g_list_append (lay->Polygon, polygon);
353   lay->PolygonN ++;
354 
355   CLEAR_FLAG (NOCOPY_FLAGS, polygon);
356 
357   if (!lay->polygon_tree)
358     lay->polygon_tree = r_create_tree (NULL, 0, 0);
359   r_insert_entry (lay->polygon_tree, (BoxType *)polygon, 0);
360   return (polygon);
361 }
362 
363 /*!
364  * \brief Moves a element to buffer without allocating memory for
365  * pins/names.
366  */
367 static void *
MoveElementToBuffer(ElementType * element)368 MoveElementToBuffer (ElementType *element)
369 {
370   /*
371    * Delete the element from the source (remove it from trees,
372    * restore to polygons)
373    */
374   r_delete_element (Source, element);
375 
376   Source->Element = g_list_remove (Source->Element, element);
377   Source->ElementN --;
378   Dest->Element = g_list_append (Dest->Element, element);
379   Dest->ElementN ++;
380 
381   PIN_LOOP (element);
382   {
383     RestoreToPolygon(Source, PIN_TYPE, element, pin);
384     CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, pin);
385   }
386   END_LOOP;
387   PAD_LOOP (element);
388   {
389     RestoreToPolygon(Source, PAD_TYPE, element, pad);
390     CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, pad);
391   }
392   END_LOOP;
393   SetElementBoundingBox (Dest, element, &PCB->Font);
394   /*
395    * Now clear the from the polygons in the destination
396    */
397   PIN_LOOP (element);
398   {
399     ClearFromPolygon (Dest, PIN_TYPE, element, pin);
400   }
401   END_LOOP;
402   PAD_LOOP (element);
403   {
404     ClearFromPolygon (Dest, PAD_TYPE, element, pad);
405   }
406   END_LOOP;
407 
408   return element;
409 }
410 
411 /*!
412  * \brief Calculates the bounding box of the buffer.
413  */
414 void
SetBufferBoundingBox(BufferType * Buffer)415 SetBufferBoundingBox (BufferType *Buffer)
416 {
417   BoxType *box = GetDataBoundingBox (Buffer->Data);
418 
419   if (box)
420     Buffer->BoundingBox = *box;
421 }
422 
423 /*!
424  * \brief Clears the contents of the paste buffer.
425  */
426 void
ClearBuffer(BufferType * Buffer)427 ClearBuffer (BufferType *Buffer)
428 {
429   if (Buffer && Buffer->Data)
430     {
431       FreeDataMemory (Buffer->Data);
432       Buffer->Data->pcb = PCB;
433     }
434 }
435 
436 /*!
437  * \brief Copies all selected and visible objects to the paste buffer.
438  *
439  * \return true if any objects have been removed.
440  */
441 void
AddSelectedToBuffer(BufferType * Buffer,Coord X,Coord Y,bool LeaveSelected)442 AddSelectedToBuffer (BufferType *Buffer, Coord X, Coord Y, bool LeaveSelected)
443 {
444   /* switch crosshair off because adding objects to the pastebuffer
445    * may change the 'valid' area for the cursor
446    */
447   if (!LeaveSelected)
448     ExtraFlag = SELECTEDFLAG;
449   notify_crosshair_change (false);
450   Source = PCB->Data;
451   Dest = Buffer->Data;
452   SelectedOperation (&AddBufferFunctions, false, ALL_TYPES);
453 
454   /* set origin to passed or current position */
455   if (X || Y)
456     {
457       Buffer->X = X;
458       Buffer->Y = Y;
459     }
460   else
461     {
462       Buffer->X = Crosshair.X;
463       Buffer->Y = Crosshair.Y;
464     }
465   notify_crosshair_change (true);
466   ExtraFlag = 0;
467 }
468 
469 /*!
470  * \brief Loads element data from file/library into buffer.
471  *
472  * Parse the file with disabled 'PCB mode' (see parser).
473  *
474  * \return false on error, if successful, update some other stuff and
475  * reposition the pastebuffer.
476  */
477 bool
LoadElementToBuffer(BufferType * Buffer,char * Name,bool FromFile)478 LoadElementToBuffer (BufferType *Buffer, char *Name, bool FromFile)
479 {
480   ElementType *element;
481 
482   ClearBuffer (Buffer);
483   if (FromFile)
484     {
485       if (!ParseElementFile (Buffer->Data, Name))
486 	{
487 	  if (Settings.ShowBottomSide)
488 	    SwapBuffer (Buffer);
489 	  SetBufferBoundingBox (Buffer);
490 	  if (Buffer->Data->ElementN)
491 	    {
492 	      element = Buffer->Data->Element->data;
493 	      Buffer->X = element->MarkX;
494 	      Buffer->Y = element->MarkY;
495 	    }
496 	  else
497 	    {
498 	      Buffer->X = 0;
499 	      Buffer->Y = 0;
500 	    }
501 	  return (true);
502 	}
503     }
504   else
505     {
506       if (!ParseLibraryEntry (Buffer->Data, Name)
507 	  && Buffer->Data->ElementN != 0)
508 	{
509 	  element = Buffer->Data->Element->data;
510 
511 	  /* always add elements using top-side coordinates */
512 	  if (Settings.ShowBottomSide)
513 	    MirrorElementCoordinates (Buffer->Data, element, 0);
514 	  SetElementBoundingBox (Buffer->Data, element, &PCB->Font);
515 
516 	  /* set buffer offset to 'mark' position */
517 	  Buffer->X = element->MarkX;
518 	  Buffer->Y = element->MarkY;
519 	  SetBufferBoundingBox (Buffer);
520 	  return (true);
521 	}
522     }
523   /* release memory which might have been acquired */
524   ClearBuffer (Buffer);
525   return (false);
526 }
527 
528 
529 typedef struct {
530   char *footprint;
531   int footprint_allocated;
532   int menu_idx;
533   int entry_idx;
534 } FootprintHashEntry;
535 
536 static FootprintHashEntry *footprint_hash = 0;
537 int footprint_hash_size = 0;
538 
539 void
clear_footprint_hash()540 clear_footprint_hash ()
541 {
542   int i;
543   if (!footprint_hash)
544     return;
545   for (i=0; i<footprint_hash_size; i++)
546     if (footprint_hash[i].footprint_allocated)
547       free (footprint_hash[i].footprint);
548   free (footprint_hash);
549   footprint_hash = NULL;
550   footprint_hash_size = 0;
551 }
552 
553 /*!
554  * \brief Used to sort footprint pointer entries.
555  *
556  * \note We include the index numbers so that same-named footprints are
557  * sorted by the library search order.
558  */
559 static int
footprint_hash_cmp(const void * va,const void * vb)560 footprint_hash_cmp (const void *va, const void *vb)
561 {
562   int i;
563   FootprintHashEntry *a = (FootprintHashEntry *)va;
564   FootprintHashEntry *b = (FootprintHashEntry *)vb;
565 
566   i = strcmp (a->footprint, b->footprint);
567   if (i == 0)
568     i = a->menu_idx - b->menu_idx;
569   if (i == 0)
570     i = a->entry_idx - b->entry_idx;
571   return i;
572 }
573 
574 void
make_footprint_hash()575 make_footprint_hash ()
576 {
577   int i, j;
578   char *fp;
579   int num_entries = 0;
580 
581   clear_footprint_hash ();
582 
583   for (i=0; i<Library.MenuN; i++)
584     for (j=0; j<Library.Menu[i].EntryN; j++)
585       num_entries ++;
586   footprint_hash = (FootprintHashEntry *)malloc (num_entries * sizeof(FootprintHashEntry));
587   num_entries = 0;
588 
589   /* There are two types of library entries.  The file-based types
590      have a Template of (char *)-1 and the AllocatedMemory is the full
591      path to the footprint file.  The m4 ones have the footprint name
592      in brackets in the description.  */
593   for (i=0; i<Library.MenuN; i++)
594     {
595 #ifdef DEBUG
596   printf("In make_footprint_hash, looking for footprints in %s\n",
597 	 Library.Menu[i].directory);
598 #endif
599 
600     for (j=0; j<Library.Menu[i].EntryN; j++)
601 	{
602 	  footprint_hash[num_entries].menu_idx = i;
603 	  footprint_hash[num_entries].entry_idx = j;
604 	  if (Library.Menu[i].Entry[j].Template == (char *) -1)
605           /* file */
606 	    {
607 #ifdef DEBUG
608 /*	      printf(" ... Examining file %s\n", Library.Menu[i].Entry[j].AllocatedMemory); */
609 #endif
610 	      fp = strrchr (Library.Menu[i].Entry[j].AllocatedMemory, '/');
611 
612 	      if (!fp)
613 		fp = strrchr (Library.Menu[i].Entry[j].AllocatedMemory, '\\');
614 
615 	      if (fp)
616 		fp ++;
617 	      else
618 		fp = Library.Menu[i].Entry[j].AllocatedMemory;
619 
620 #ifdef DEBUG
621 /* 	      printf(" ... found file footprint %s\n",  fp); */
622 #endif
623 
624 	      footprint_hash[num_entries].footprint = fp;
625 	      footprint_hash[num_entries].footprint_allocated = 0;
626 	    }
627 	  else
628           /* m4 */
629 	    {
630 	      fp = strrchr (Library.Menu[i].Entry[j].Description, '[');
631 	      if (fp)
632 		{
633 		  footprint_hash[num_entries].footprint = strdup (fp+1);
634 		  footprint_hash[num_entries].footprint_allocated = 1;
635 		  fp = strchr (footprint_hash[num_entries].footprint, ']');
636 		  if (fp)
637 		    *fp = 0;
638 		}
639 	      else
640 		{
641 		  fp = Library.Menu[i].Entry[j].Description;
642 		  footprint_hash[num_entries].footprint = fp;
643 		  footprint_hash[num_entries].footprint_allocated = 0;
644 		}
645 	    }
646 	  num_entries ++;
647 	}
648     }
649 
650   footprint_hash_size = num_entries;
651   qsort (footprint_hash, num_entries, sizeof(footprint_hash[0]), footprint_hash_cmp);
652 /*
653 #ifdef DEBUG
654   printf("       found footprints:  \n");
655   for (i=0; i<num_entries; i++)
656     printf("[%s]\n", footprint_hash[i].footprint);
657 #endif
658 */
659 }
660 
661 /*!
662  * \brief Searches for the given element by "footprint" name, and loads
663  * it into the buffer.
664  *
665  * Figuring out which library entry is the one we want is a little
666  * tricky.  For file-based footprints, it's just a matter of finding
667  * the first match in the search list.  For m4-based footprints you
668  * need to know what magic to pass to the m4 functions.  Fortunately,
669  * the footprint needed is determined when we build the m4 libraries
670  * and stored as a comment in the description, so we can search for
671  * that to find the magic we need.  We use a hash to store the
672  * corresponding footprints and pointers to the library tree so we can
673  * quickly find the various bits we need to load a given
674  * footprint.
675  */
676 FootprintHashEntry *
search_footprint_hash(const char * footprint)677 search_footprint_hash (const char *footprint)
678 {
679   int i, min, max, c;
680 
681   /* Standard binary search */
682 
683   min = -1;
684   max = footprint_hash_size;
685 
686   while (max - min > 1)
687     {
688       i = (min+max)/2;
689       c = strcmp (footprint, footprint_hash[i].footprint);
690       if (c < 0)
691 	max = i;
692       else if (c > 0)
693 	min = i;
694       else
695 	{
696 	  /* We want to return the first match, not just any match.  */
697 	  while (i > 0
698 		 && strcmp (footprint, footprint_hash[i-1].footprint) == 0)
699 	    i--;
700 	  return & footprint_hash[i];
701 	}
702     }
703   return NULL;
704 }
705 
706 /*!
707  * \brief .
708  *
709  * \return zero on success, non-zero on error.
710  */
711 int
LoadFootprintByName(BufferType * Buffer,char * Footprint)712 LoadFootprintByName (BufferType *Buffer, char *Footprint)
713 {
714   int i;
715   FootprintHashEntry *fpe;
716   LibraryMenuType *menu;
717   LibraryEntryType *entry;
718   char *with_fp = NULL;
719 
720   if (!footprint_hash)
721     make_footprint_hash ();
722 
723   fpe = search_footprint_hash (Footprint);
724   if (!fpe)
725     {
726       with_fp = Concat (Footprint, ".fp", NULL);
727       fpe = search_footprint_hash (with_fp);
728       if (fpe)
729 	Footprint = with_fp;
730     }
731   if (!fpe)
732     {
733       Message(_("Unable to load footprint %s\n"), Footprint);
734       return 1;
735     }
736 
737   menu = & Library.Menu[fpe->menu_idx];
738   entry = & menu->Entry[fpe->entry_idx];
739 
740   if (entry->Template == (char *) -1)
741     {
742       i = LoadElementToBuffer (Buffer, entry->AllocatedMemory, true);
743       if (with_fp)
744 	free (with_fp);
745       return i ? 0 : 1;
746     }
747   else
748     {
749       char *args;
750 
751       args = Concat("'", EMPTY (entry->Template), "' '",
752 		    EMPTY (entry->Value), "' '", EMPTY (entry->Package), "'", NULL);
753       i = LoadElementToBuffer (Buffer, args, false);
754 
755       free (args);
756       if (with_fp)
757 	free (with_fp);
758       return i ? 0 : 1;
759     }
760 
761 #ifdef DEBUG
762   {
763     int j;
764     printf("Library path: %s\n", Settings.LibraryPath);
765     printf("Library tree: %s\n", Settings.LibraryTree);
766 
767     printf("Library:\n");
768     for (i=0; i<Library.MenuN; i++)
769       {
770 	printf("  [%02d] Name: %s\n", i, Library.Menu[i].Name);
771 	printf("       Dir:  %s\n", Library.Menu[i].directory);
772 	printf("       Sty:  %s\n", Library.Menu[i].Style);
773 	for (j=0; j<Library.Menu[i].EntryN; j++)
774 	  {
775 	    printf("       [%02d] E: %s\n", j, Library.Menu[i].Entry[j].ListEntry);
776 	    if (Library.Menu[i].Entry[j].Template == (char *) -1)
777 	      printf("            A: %s\n", Library.Menu[i].Entry[j].AllocatedMemory);
778 	    else
779 	      {
780 		printf("            T: %s\n", Library.Menu[i].Entry[j].Template);
781 		printf("            P: %s\n", Library.Menu[i].Entry[j].Package);
782 		printf("            V: %s\n", Library.Menu[i].Entry[j].Value);
783 		printf("            D: %s\n", Library.Menu[i].Entry[j].Description);
784 	      }
785 	    if (j == 10)
786 	      break;
787 	  }
788       }
789   }
790 #endif
791 }
792 
793 
794 static const char loadfootprint_syntax[] =
795   N_("LoadFootprint(filename[,refdes,value])");
796 
797 static const char loadfootprint_help[] =
798   N_("Loads a single footprint by name.");
799 
800 /* %start-doc actions LoadFootprint
801 
802 Loads a single footprint by name, rather than by reference or through
803 the library.  If a refdes and value are specified, those are inserted
804 into the footprint as well.  The footprint remains in the paste buffer.
805 
806 %end-doc */
807 
808 /*!
809  * \brief This action is called from ActionElementAddIf().
810  */
811 int
LoadFootprint(int argc,char ** argv,Coord x,Coord y)812 LoadFootprint (int argc, char **argv, Coord x, Coord y)
813 {
814   char *name = ARG(0);
815   char *refdes = ARG(1);
816   char *value = ARG(2);
817   ElementType *e;
818 
819   if (!name)
820     AFAIL (loadfootprint);
821 
822   if (LoadFootprintByName (PASTEBUFFER, name))
823     return 1;
824 
825   if (PASTEBUFFER->Data->ElementN == 0)
826     {
827       Message(_("Footprint %s contains no elements"), name);
828       return 1;
829     }
830   if (PASTEBUFFER->Data->ElementN > 1)
831     {
832       Message(_("Footprint %s contains multiple elements"), name);
833       return 1;
834     }
835 
836   e = PASTEBUFFER->Data->Element->data;
837 
838   if (e->Name[0].TextString)
839     free (e->Name[0].TextString);
840   e->Name[0].TextString = strdup (name);
841 
842   if (e->Name[1].TextString)
843     free (e->Name[1].TextString);
844   e->Name[1].TextString = refdes ? strdup (refdes) : 0;
845 
846   if (e->Name[2].TextString)
847     free (e->Name[2].TextString);
848   e->Name[2].TextString = value ? strdup (value) : 0;
849 
850   return 0;
851 }
852 
853 /*!
854  * \brief Break buffer element into pieces.
855  */
856 bool
SmashBufferElement(BufferType * Buffer)857 SmashBufferElement (BufferType *Buffer)
858 {
859   ElementType *element;
860   Cardinal group;
861   LayerType *top_layer, *bottom_layer;
862 
863   if (Buffer->Data->ElementN != 1)
864     {
865       Message (_("Error!  Buffer doesn't contain a single element\n"));
866       return (false);
867     }
868   /*
869    * At this point the buffer should contain just a single element.
870    * Now we detach the single element from the buffer and then clear the
871    * buffer, ready to receive the smashed elements.  As a result of detaching
872    * it the single element is orphaned from the buffer and thus will not be
873    * free()'d by FreeDataMemory (called via ClearBuffer).  This leaves it
874    * around for us to smash bits off it.  It then becomes our responsibility,
875    * however, to free the single element when we're finished with it.
876    */
877   element = Buffer->Data->Element->data;
878   Buffer->Data->Element = NULL;
879   Buffer->Data->ElementN = 0;
880   ClearBuffer (Buffer);
881   ELEMENTLINE_LOOP (element);
882   {
883     CreateNewLineOnLayer (&Buffer->Data->SILKLAYER,
884 			  line->Point1.X, line->Point1.Y,
885 			  line->Point2.X, line->Point2.Y,
886 			  line->Thickness, 0, NoFlags ());
887     if (line)
888       line->Number = STRDUP (NAMEONPCB_NAME (element));
889   }
890   END_LOOP;
891   ARC_LOOP (element);
892   {
893     CreateNewArcOnLayer (&Buffer->Data->SILKLAYER,
894 			 arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle,
895 			 arc->Delta, arc->Thickness, 0, NoFlags ());
896   }
897   END_LOOP;
898   PIN_LOOP (element);
899   {
900     FlagType f = NoFlags ();
901     AddFlags (f, VIAFLAG);
902     if (TEST_FLAG (HOLEFLAG, pin))
903       AddFlags (f, HOLEFLAG);
904 
905     CreateNewVia (Buffer->Data, pin->X, pin->Y,
906 		  pin->Thickness, pin->Clearance, pin->Mask,
907 		  pin->DrillingHole, pin->Number, f);
908   }
909   END_LOOP;
910   group = GetLayerGroupNumberBySide (SWAP_IDENT ? BOTTOM_SIDE : TOP_SIDE);
911   top_layer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
912   group = GetLayerGroupNumberBySide (SWAP_IDENT ? TOP_SIDE : BOTTOM_SIDE);
913   bottom_layer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
914   PAD_LOOP (element);
915   {
916     LineType *line;
917     line = CreateNewLineOnLayer (TEST_FLAG (ONSOLDERFLAG, pad) ? bottom_layer : top_layer,
918 				 pad->Point1.X, pad->Point1.Y,
919 				 pad->Point2.X, pad->Point2.Y,
920 				 pad->Thickness, pad->Clearance, NoFlags ());
921     if (line)
922       line->Number = STRDUP (pad->Number);
923   }
924   END_LOOP;
925   FreeElementMemory (element);
926   g_slice_free (ElementType, element);
927   return (true);
928 }
929 
930 /*!
931  * \brief See if a polygon is a rectangle.
932  *
933  * If so, canonicalize it.
934  */
935 
936 static int
polygon_is_rectangle(PolygonType * poly)937 polygon_is_rectangle (PolygonType *poly)
938 {
939   int i, best;
940   PointType temp[4];
941   if (poly->PointN != 4 || poly->HoleIndexN != 0)
942     return 0;
943   best = 0;
944   for (i=1; i<4; i++)
945     if (poly->Points[i].X < poly->Points[best].X
946 	|| poly->Points[i].Y < poly->Points[best].Y)
947       best = i;
948   for (i=0; i<4; i++)
949     temp[i] = poly->Points[(i+best)%4];
950   if (temp[0].X == temp[1].X)
951     memcpy (poly->Points, temp, sizeof(temp));
952   else
953     {
954       /* reverse them */
955       poly->Points[0] = temp[0];
956       poly->Points[1] = temp[3];
957       poly->Points[2] = temp[2];
958       poly->Points[3] = temp[1];
959     }
960   if (poly->Points[0].X == poly->Points[1].X
961       && poly->Points[1].Y == poly->Points[2].Y
962       && poly->Points[2].X == poly->Points[3].X
963       && poly->Points[3].Y == poly->Points[0].Y)
964     return 1;
965   return 0;
966 }
967 
968 /*!
969  * \brief Convert buffer contents into an element.
970  */
971 bool
ConvertBufferToElement(BufferType * Buffer)972 ConvertBufferToElement (BufferType *Buffer)
973 {
974   ElementType *Element;
975   Cardinal group;
976   Cardinal pin_n = 1;
977   bool hasParts = false, crooked = false;
978   int onsolder;
979   bool warned = false;
980 
981   if (Buffer->Data->pcb == 0)
982     Buffer->Data->pcb = PCB;
983 
984   Element = CreateNewElement (PCB->Data, &PCB->Font, NoFlags (),
985 			      NULL, NULL, NULL, PASTEBUFFER->X,
986 			      PASTEBUFFER->Y, 0, 100,
987 			      MakeFlags (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG),
988 			      false);
989   if (!Element)
990     return (false);
991   VIA_LOOP (Buffer->Data);
992   {
993     char num[8];
994     if (via->Mask < via->Thickness)
995       via->Mask = via->Thickness + 2 * MASKFRAME;
996     if (via->Name)
997       CreateNewPin (Element, via->X, via->Y, via->Thickness,
998 		    via->Clearance, via->Mask, via->DrillingHole,
999 		    NULL, via->Name, MaskFlags (via->Flags,
1000 						VIAFLAG | NOCOPY_FLAGS |
1001 						SELECTEDFLAG | WARNFLAG));
1002     else
1003       {
1004 	sprintf (num, "%d", pin_n++);
1005 	CreateNewPin (Element, via->X, via->Y, via->Thickness,
1006 		      via->Clearance, via->Mask, via->DrillingHole,
1007 		      NULL, num, MaskFlags (via->Flags,
1008 					    VIAFLAG | NOCOPY_FLAGS | SELECTEDFLAG
1009 					    | WARNFLAG));
1010       }
1011     hasParts = true;
1012   }
1013   END_LOOP;
1014 
1015   for (onsolder = 0; onsolder < 2; onsolder ++)
1016     {
1017       int side;
1018       int onsolderflag;
1019 
1020       if ((!onsolder) == (!SWAP_IDENT))
1021 	{
1022 	  side = TOP_SIDE;
1023 	  onsolderflag = NOFLAG;
1024 	}
1025       else
1026 	{
1027 	  side = BOTTOM_SIDE;
1028 	  onsolderflag = ONSOLDERFLAG;
1029 	}
1030 
1031 #define MAYBE_WARN() \
1032 	  if (onsolder && !hasParts && !warned) \
1033 	    { \
1034 	      warned = true; \
1035 	      Message \
1036 		(_("Warning: All of the pads are on the opposite\n" \
1037 		   "side from the component - that's probably not what\n" \
1038 		   "you wanted\n")); \
1039 	    } \
1040 
1041       /* get the component-side SM pads */
1042       group = GetLayerGroupNumberBySide (side);
1043       GROUP_LOOP (Buffer->Data, group);
1044       {
1045 	char num[8];
1046 	LINE_LOOP (layer);
1047 	{
1048 	  sprintf (num, "%d", pin_n++);
1049 	  CreateNewPad (Element, line->Point1.X,
1050 			line->Point1.Y, line->Point2.X,
1051 			line->Point2.Y, line->Thickness,
1052 			line->Clearance,
1053 			line->Thickness + line->Clearance, NULL,
1054 			line->Number ? line->Number : num,
1055 			MakeFlags (onsolderflag));
1056 	  MAYBE_WARN();
1057 	  hasParts = true;
1058 	}
1059 	END_LOOP;
1060 	POLYGON_LOOP (layer);
1061 	{
1062 	  Coord x1, y1, x2, y2, w, h, t;
1063 
1064 	  if (! polygon_is_rectangle (polygon))
1065 	    {
1066 	      crooked = true;
1067 	      continue;
1068 	    }
1069 
1070 	  w = polygon->Points[2].X - polygon->Points[0].X;
1071 	  h = polygon->Points[1].Y - polygon->Points[0].Y;
1072 	  t = (w < h) ? w : h;
1073 	  x1 = polygon->Points[0].X + t/2;
1074 	  y1 = polygon->Points[0].Y + t/2;
1075 	  x2 = x1 + (w-t);
1076 	  y2 = y1 + (h-t);
1077 
1078 	  sprintf (num, "%d", pin_n++);
1079 	  CreateNewPad (Element,
1080 			x1, y1, x2, y2, t,
1081 			2 * Settings.Keepaway,
1082 			t + Settings.Keepaway,
1083 			NULL, num,
1084 			MakeFlags (SQUAREFLAG | onsolderflag));
1085 	  MAYBE_WARN();
1086 	  hasParts = true;
1087 	}
1088 	END_LOOP;
1089       }
1090       END_LOOP;
1091     }
1092 
1093   /* now add the silkscreen. NOTE: elements must have pads or pins too */
1094   LINE_LOOP (&Buffer->Data->SILKLAYER);
1095   {
1096     if (line->Number && !NAMEONPCB_NAME (Element))
1097       NAMEONPCB_NAME (Element) = strdup (line->Number);
1098     CreateNewLineInElement (Element, line->Point1.X,
1099 			    line->Point1.Y, line->Point2.X,
1100 			    line->Point2.Y, line->Thickness);
1101     hasParts = true;
1102   }
1103   END_LOOP;
1104   ARC_LOOP (&Buffer->Data->SILKLAYER);
1105   {
1106     CreateNewArcInElement (Element, arc->X, arc->Y, arc->Width,
1107 			   arc->Height, arc->StartAngle, arc->Delta,
1108 			   arc->Thickness);
1109     hasParts = true;
1110   }
1111   END_LOOP;
1112   if (!hasParts)
1113     {
1114       DestroyObject (PCB->Data, ELEMENT_TYPE, Element, Element, Element);
1115       Message (_("There was nothing to convert!\n"
1116 		 "Elements must have some silk, pads or pins.\n"));
1117       return (false);
1118     }
1119   if (crooked)
1120      Message (_("There were polygons that can't be made into pins!\n"
1121                 "So they were not included in the element\n"));
1122   Element->MarkX = Buffer->X;
1123   Element->MarkY = Buffer->Y;
1124   if (SWAP_IDENT)
1125     SET_FLAG (ONSOLDERFLAG, Element);
1126   SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
1127   ClearBuffer (Buffer);
1128   MoveObjectToBuffer (Buffer->Data, PCB->Data, ELEMENT_TYPE, Element, Element,
1129 		      Element);
1130   SetBufferBoundingBox (Buffer);
1131   return (true);
1132 }
1133 
1134 /*!
1135  * \brief Load PCB into buffer.
1136  *
1137  * Parse the file with enabled 'PCB mode' (see parser).
1138  * If successful, update some other stuff.
1139  */
1140 bool
LoadLayoutToBuffer(BufferType * Buffer,char * Filename)1141 LoadLayoutToBuffer (BufferType *Buffer, char *Filename)
1142 {
1143   PCBType *newPCB = CreateNewPCB ();
1144 
1145   /* new data isn't added to the undo list */
1146   if (!ParsePCB (newPCB, Filename))
1147     {
1148       /* clear data area and replace pointer */
1149       ClearBuffer (Buffer);
1150       free (Buffer->Data);
1151       Buffer->Data = newPCB->Data;
1152       newPCB->Data = NULL;
1153       Buffer->X = newPCB->CursorX;
1154       Buffer->Y = newPCB->CursorY;
1155       RemovePCB (newPCB);
1156       Buffer->Data->pcb = PCB;
1157       return (true);
1158     }
1159 
1160   /* release unused memory */
1161   RemovePCB (newPCB);
1162       Buffer->Data->pcb = PCB;
1163   return (false);
1164 }
1165 
1166 /*!
1167  * \brief Rotates the contents of the pastebuffer.
1168  */
1169 void
RotateBuffer(BufferType * Buffer,BYTE Number)1170 RotateBuffer (BufferType *Buffer, BYTE Number)
1171 {
1172   /* rotate vias */
1173   VIA_LOOP (Buffer->Data);
1174   {
1175     r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
1176     ROTATE_VIA_LOWLEVEL (via, Buffer->X, Buffer->Y, Number);
1177     SetPinBoundingBox (via);
1178     r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
1179   }
1180   END_LOOP;
1181 
1182   /* elements */
1183   ELEMENT_LOOP (Buffer->Data);
1184   {
1185     RotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
1186 			   Number);
1187   }
1188   END_LOOP;
1189 
1190   /* all layer related objects */
1191   ALLLINE_LOOP (Buffer->Data);
1192   {
1193     r_delete_entry (layer->line_tree, (BoxType *)line);
1194     RotateLineLowLevel (line, Buffer->X, Buffer->Y, Number);
1195     r_insert_entry (layer->line_tree, (BoxType *)line, 0);
1196   }
1197   ENDALL_LOOP;
1198   ALLARC_LOOP (Buffer->Data);
1199   {
1200     r_delete_entry (layer->arc_tree, (BoxType *)arc);
1201     RotateArcLowLevel (arc, Buffer->X, Buffer->Y, Number);
1202     r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
1203   }
1204   ENDALL_LOOP;
1205   ALLTEXT_LOOP (Buffer->Data);
1206   {
1207     r_delete_entry (layer->text_tree, (BoxType *)text);
1208     RotateTextLowLevel (text, Buffer->X, Buffer->Y, Number);
1209     r_insert_entry (layer->text_tree, (BoxType *)text, 0);
1210   }
1211   ENDALL_LOOP;
1212   ALLPOLYGON_LOOP (Buffer->Data);
1213   {
1214     r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
1215     RotatePolygonLowLevel (polygon, Buffer->X, Buffer->Y, Number);
1216     r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
1217   }
1218   ENDALL_LOOP;
1219 
1220   /* finally the origin and the bounding box */
1221   ROTATE (Buffer->X, Buffer->Y, Buffer->X, Buffer->Y, Number);
1222   RotateBoxLowLevel (&Buffer->BoundingBox, Buffer->X, Buffer->Y, Number);
1223   crosshair_update_range();
1224 }
1225 
1226 static void
free_rotate(Coord * x,Coord * y,Coord cx,Coord cy,double cosa,double sina)1227 free_rotate (Coord *x, Coord *y, Coord cx, Coord cy, double cosa, double sina)
1228 {
1229   double nx, ny;
1230   Coord px = *x - cx;
1231   Coord py = *y - cy;
1232 
1233   nx = px * cosa + py * sina;
1234   ny = py * cosa - px * sina;
1235 
1236   *x = nx + cx;
1237   *y = ny + cy;
1238 }
1239 
1240 void
FreeRotateElementLowLevel(DataType * Data,ElementType * Element,Coord X,Coord Y,double cosa,double sina,Angle angle)1241 FreeRotateElementLowLevel (DataType *Data, ElementType *Element,
1242 			   Coord X, Coord Y,
1243 			   double cosa, double sina, Angle angle)
1244 {
1245   /* solder side objects need a different orientation */
1246 
1247   /* the text subroutine decides by itself if the direction
1248    * is to be corrected
1249    */
1250 #if 0
1251   ELEMENTTEXT_LOOP (Element);
1252   {
1253     if (Data && Data->name_tree[n])
1254       r_delete_entry (Data->name_tree[n], (BoxType *)text);
1255     RotateTextLowLevel (text, X, Y, Number);
1256   }
1257   END_LOOP;
1258 #endif
1259   ELEMENTLINE_LOOP (Element);
1260   {
1261     free_rotate (&line->Point1.X, &line->Point1.Y, X, Y, cosa, sina);
1262     free_rotate (&line->Point2.X, &line->Point2.Y, X, Y, cosa, sina);
1263     SetLineBoundingBox (line);
1264   }
1265   END_LOOP;
1266   PIN_LOOP (Element);
1267   {
1268     /* pre-delete the pins from the pin-tree before their coordinates change */
1269     if (Data)
1270       r_delete_entry (Data->pin_tree, (BoxType *)pin);
1271     RestoreToPolygon (Data, PIN_TYPE, Element, pin);
1272     free_rotate (&pin->X, &pin->Y, X, Y, cosa, sina);
1273     SetPinBoundingBox (pin);
1274   }
1275   END_LOOP;
1276   PAD_LOOP (Element);
1277   {
1278     /* pre-delete the pads before their coordinates change */
1279     if (Data)
1280       r_delete_entry (Data->pad_tree, (BoxType *)pad);
1281     RestoreToPolygon (Data, PAD_TYPE, Element, pad);
1282     free_rotate (&pad->Point1.X, &pad->Point1.Y, X, Y, cosa, sina);
1283     free_rotate (&pad->Point2.X, &pad->Point2.Y, X, Y, cosa, sina);
1284     SetLineBoundingBox ((LineType *) pad);
1285   }
1286   END_LOOP;
1287   ARC_LOOP (Element);
1288   {
1289     free_rotate (&arc->X, &arc->Y, X, Y, cosa, sina);
1290     arc->StartAngle = NormalizeAngle (arc->StartAngle + angle);
1291   }
1292   END_LOOP;
1293 
1294   free_rotate (&Element->MarkX, &Element->MarkY, X, Y, cosa, sina);
1295   SetElementBoundingBox (Data, Element, &PCB->Font);
1296   ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element);
1297 }
1298 
1299 void
FreeRotateBuffer(BufferType * Buffer,Angle angle)1300 FreeRotateBuffer (BufferType *Buffer, Angle angle)
1301 {
1302   double cosa, sina;
1303 
1304   cosa = cos(angle * M_PI/180.0);
1305   sina = sin(angle * M_PI/180.0);
1306 
1307   /* rotate vias */
1308   VIA_LOOP (Buffer->Data);
1309   {
1310     r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
1311     free_rotate (&via->X, &via->Y, Buffer->X, Buffer->Y, cosa, sina);
1312     SetPinBoundingBox (via);
1313     r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
1314   }
1315   END_LOOP;
1316 
1317   /* elements */
1318   ELEMENT_LOOP (Buffer->Data);
1319   {
1320     FreeRotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
1321 			       cosa, sina, angle);
1322   }
1323   END_LOOP;
1324 
1325   /* all layer related objects */
1326   ALLLINE_LOOP (Buffer->Data);
1327   {
1328     r_delete_entry (layer->line_tree, (BoxType *)line);
1329     free_rotate (&line->Point1.X, &line->Point1.Y, Buffer->X, Buffer->Y, cosa, sina);
1330     free_rotate (&line->Point2.X, &line->Point2.Y, Buffer->X, Buffer->Y, cosa, sina);
1331     SetLineBoundingBox (line);
1332     r_insert_entry (layer->line_tree, (BoxType *)line, 0);
1333   }
1334   ENDALL_LOOP;
1335   ALLARC_LOOP (Buffer->Data);
1336   {
1337     r_delete_entry (layer->arc_tree, (BoxType *)arc);
1338     free_rotate (&arc->X, &arc->Y, Buffer->X, Buffer->Y, cosa, sina);
1339     arc->StartAngle = NormalizeAngle (arc->StartAngle + angle);
1340     r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
1341   }
1342   ENDALL_LOOP;
1343   /* FIXME: rotate text */
1344   ALLPOLYGON_LOOP (Buffer->Data);
1345   {
1346     r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
1347     POLYGONPOINT_LOOP (polygon);
1348     {
1349       free_rotate (&point->X, &point->Y, Buffer->X, Buffer->Y, cosa, sina);
1350     }
1351     END_LOOP;
1352     SetPolygonBoundingBox (polygon);
1353     r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
1354   }
1355   ENDALL_LOOP;
1356 
1357   SetBufferBoundingBox (Buffer);
1358   crosshair_update_range();
1359 }
1360 
1361 
1362 /* -------------------------------------------------------------------------- */
1363 
1364 static const char freerotatebuffer_syntax[] =
1365   N_("FreeRotateBuffer([Angle])");
1366 
1367 static const char freerotatebuffer_help[] =
1368   N_("Rotates the current paste buffer contents by the specified angle.  The\n"
1369   "angle is given in degrees.  If no angle is given, the user is prompted\n"
1370   "for one.\n");
1371 
1372 /* %start-doc actions FreeRotateBuffer
1373 
1374 Rotates the contents of the pastebuffer by an arbitrary angle.  If no
1375 angle is given, the user is prompted for one.
1376 
1377 %end-doc */
1378 
1379 int
ActionFreeRotateBuffer(int argc,char ** argv,Coord x,Coord y)1380 ActionFreeRotateBuffer(int argc, char **argv, Coord x, Coord y)
1381 {
1382   char *angle_s;
1383 
1384   if (argc < 1)
1385     angle_s = gui->prompt_for (_("Enter Rotation (degrees, CCW):"), "0");
1386   else
1387     angle_s = argv[0];
1388 
1389   notify_crosshair_change (false);
1390   FreeRotateBuffer(PASTEBUFFER, strtod(angle_s, 0));
1391   notify_crosshair_change (true);
1392   return 0;
1393 }
1394 
1395 /*!
1396  * \brief Initializes the buffers by allocating memory.
1397  */
1398 void
InitBuffers(void)1399 InitBuffers (void)
1400 {
1401   int i;
1402 
1403   for (i = 0; i < MAX_BUFFER; i++)
1404     Buffers[i].Data = CreateNewBuffer ();
1405 }
1406 
1407 void
UninitBuffers(void)1408 UninitBuffers (void)
1409 {
1410   int i;
1411 
1412   for (i = 0; i < MAX_BUFFER; i++)
1413     {
1414       ClearBuffer (Buffers+i);
1415       free (Buffers[i].Data);
1416     }
1417 }
1418 
1419 void
SwapBuffers(void)1420 SwapBuffers (void)
1421 {
1422   int i;
1423 
1424   for (i = 0; i < MAX_BUFFER; i++)
1425     SwapBuffer (&Buffers[i]);
1426   crosshair_update_range();
1427 }
1428 
1429 void
MirrorBuffer(BufferType * Buffer)1430 MirrorBuffer (BufferType *Buffer)
1431 {
1432   int i;
1433 
1434   if (Buffer->Data->ElementN)
1435     {
1436       Message (_("You can't mirror a buffer that has elements!\n"));
1437       return;
1438     }
1439   for (i = 0; i < max_copper_layer + SILK_LAYER; i++)
1440     {
1441       LayerType *layer = Buffer->Data->Layer + i;
1442       if (layer->TextN)
1443 	{
1444 	  Message (_("You can't mirror a buffer that has text!\n"));
1445 	  return;
1446 	}
1447     }
1448   /* set buffer offset to 'mark' position */
1449   Buffer->X = SWAP_X (Buffer->X);
1450   Buffer->Y = SWAP_Y (Buffer->Y);
1451   VIA_LOOP (Buffer->Data);
1452   {
1453     via->X = SWAP_X (via->X);
1454     via->Y = SWAP_Y (via->Y);
1455   }
1456   END_LOOP;
1457   ALLLINE_LOOP (Buffer->Data);
1458   {
1459     line->Point1.X = SWAP_X (line->Point1.X);
1460     line->Point1.Y = SWAP_Y (line->Point1.Y);
1461     line->Point2.X = SWAP_X (line->Point2.X);
1462     line->Point2.Y = SWAP_Y (line->Point2.Y);
1463   }
1464   ENDALL_LOOP;
1465   ALLARC_LOOP (Buffer->Data);
1466   {
1467     r_delete_entry(layer->arc_tree, (BoxType*)arc);
1468     arc->X = SWAP_X (arc->X);
1469     arc->Y = SWAP_Y (arc->Y);
1470     arc->StartAngle = SWAP_ANGLE (arc->StartAngle);
1471     arc->Delta = SWAP_DELTA (arc->Delta);
1472     SetArcBoundingBox (arc);
1473     r_insert_entry(layer->arc_tree, (BoxType*)arc, 0);
1474   }
1475   ENDALL_LOOP;
1476   ALLPOLYGON_LOOP (Buffer->Data);
1477   {
1478     r_delete_entry(layer->polygon_tree, (BoxType*)polygon);
1479     POLYGONPOINT_LOOP (polygon);
1480     {
1481       point->X = SWAP_X (point->X);
1482       point->Y = SWAP_Y (point->Y);
1483     }
1484     END_LOOP;
1485     SetPolygonBoundingBox (polygon);
1486     r_insert_entry(layer->polygon_tree, (BoxType*)polygon, 0);
1487   }
1488   ENDALL_LOOP;
1489   SetBufferBoundingBox (Buffer);
1490   crosshair_update_range();
1491 }
1492 
1493 
1494 /*!
1495  * \brief Flip components/tracks from one side to the other.
1496  */
1497 static void
SwapBuffer(BufferType * Buffer)1498 SwapBuffer (BufferType *Buffer)
1499 {
1500   int j, k;
1501   Cardinal top_group, bottom_group;
1502   LayerType swap;
1503 
1504   ELEMENT_LOOP (Buffer->Data);
1505   {
1506     r_delete_element (Buffer->Data, element);
1507     MirrorElementCoordinates (Buffer->Data, element, 0);
1508   }
1509   END_LOOP;
1510   /* set buffer offset to 'mark' position */
1511   Buffer->X = SWAP_X (Buffer->X);
1512   Buffer->Y = SWAP_Y (Buffer->Y);
1513   VIA_LOOP (Buffer->Data);
1514   {
1515     r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
1516     via->X = SWAP_X (via->X);
1517     via->Y = SWAP_Y (via->Y);
1518     SetPinBoundingBox (via);
1519     r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
1520   }
1521   END_LOOP;
1522   ALLLINE_LOOP (Buffer->Data);
1523   {
1524     r_delete_entry (layer->line_tree, (BoxType *)line);
1525     line->Point1.X = SWAP_X (line->Point1.X);
1526     line->Point1.Y = SWAP_Y (line->Point1.Y);
1527     line->Point2.X = SWAP_X (line->Point2.X);
1528     line->Point2.Y = SWAP_Y (line->Point2.Y);
1529     SetLineBoundingBox (line);
1530     r_insert_entry (layer->line_tree, (BoxType *)line, 0);
1531   }
1532   ENDALL_LOOP;
1533   ALLARC_LOOP (Buffer->Data);
1534   {
1535     r_delete_entry (layer->arc_tree, (BoxType *)arc);
1536     arc->X = SWAP_X (arc->X);
1537     arc->Y = SWAP_Y (arc->Y);
1538     arc->StartAngle = SWAP_ANGLE (arc->StartAngle);
1539     arc->Delta = SWAP_DELTA (arc->Delta);
1540     SetArcBoundingBox (arc);
1541     r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
1542   }
1543   ENDALL_LOOP;
1544   ALLPOLYGON_LOOP (Buffer->Data);
1545   {
1546     r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
1547     POLYGONPOINT_LOOP (polygon);
1548     {
1549       point->X = SWAP_X (point->X);
1550       point->Y = SWAP_Y (point->Y);
1551     }
1552     END_LOOP;
1553     SetPolygonBoundingBox (polygon);
1554     r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
1555     /* hmmm, how to handle clip */
1556   }
1557   ENDALL_LOOP;
1558   ALLTEXT_LOOP (Buffer->Data);
1559   {
1560     r_delete_entry (layer->text_tree, (BoxType *)text);
1561     text->X = SWAP_X (text->X);
1562     text->Y = SWAP_Y (text->Y);
1563     TOGGLE_FLAG (ONSOLDERFLAG, text);
1564     SetTextBoundingBox (&PCB->Font, text);
1565     r_insert_entry (layer->text_tree, (BoxType *)text, 0);
1566   }
1567   ENDALL_LOOP;
1568   /* swap silkscreen layers */
1569   swap = Buffer->Data->Layer[bottom_silk_layer];
1570   Buffer->Data->Layer[bottom_silk_layer] =
1571     Buffer->Data->Layer[top_silk_layer];
1572   Buffer->Data->Layer[top_silk_layer] = swap;
1573 
1574   /* swap layer groups when balanced */
1575   top_group = GetLayerGroupNumberBySide (TOP_SIDE);
1576   bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
1577   if (PCB->LayerGroups.Number[top_group] == PCB->LayerGroups.Number[bottom_group])
1578     {
1579       for (j = k = 0; j < PCB->LayerGroups.Number[bottom_group]; j++)
1580 	{
1581 	  int t1, t2;
1582 	  Cardinal top_number = PCB->LayerGroups.Entries[top_group][k];
1583 	  Cardinal bottom_number = PCB->LayerGroups.Entries[bottom_group][j];
1584 
1585 	  if (bottom_number >= max_copper_layer)
1586 	    continue;
1587 	  swap = Buffer->Data->Layer[bottom_number];
1588 
1589 	  while (top_number >= max_copper_layer)
1590 	    {
1591 	      k++;
1592 	      top_number = PCB->LayerGroups.Entries[top_group][k];
1593 	    }
1594 	  Buffer->Data->Layer[bottom_number] = Buffer->Data->Layer[top_number];
1595 	  Buffer->Data->Layer[top_number] = swap;
1596 	  k++;
1597 	  /* move the thermal flags with the layers */
1598 	  ALLPIN_LOOP (Buffer->Data);
1599 	  {
1600 	    t1 = TEST_THERM (bottom_number, pin);
1601 	    t2 = TEST_THERM (top_number, pin);
1602 	    ASSIGN_THERM (bottom_number, t2, pin);
1603 	    ASSIGN_THERM (top_number, t1, pin);
1604 	  }
1605 	  ENDALL_LOOP;
1606 	  VIA_LOOP (Buffer->Data);
1607 	  {
1608 	    t1 = TEST_THERM (bottom_number, via);
1609 	    t2 = TEST_THERM (top_number, via);
1610 	    ASSIGN_THERM (bottom_number, t2, via);
1611 	    ASSIGN_THERM (top_number, t1, via);
1612 	  }
1613 	  END_LOOP;
1614 	}
1615     }
1616   SetBufferBoundingBox (Buffer);
1617   crosshair_update_range();
1618 }
1619 
1620 /*!
1621  * \brief Moves the passed object to the passed buffer and removes it
1622  * from its original place.
1623  */
1624 void *
MoveObjectToBuffer(DataType * Destination,DataType * Src,int Type,void * Ptr1,void * Ptr2,void * Ptr3)1625 MoveObjectToBuffer (DataType *Destination, DataType *Src,
1626 		    int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1627 {
1628   /* setup local identifiers used by move operations */
1629   Dest = Destination;
1630   Source = Src;
1631   return (ObjectOperation (&MoveBufferFunctions, Type, Ptr1, Ptr2, Ptr3));
1632 }
1633 
1634 /*!
1635  * \brief Adds the passed object to the passed buffer.
1636  */
1637 void *
CopyObjectToBuffer(DataType * Destination,DataType * Src,int Type,void * Ptr1,void * Ptr2,void * Ptr3)1638 CopyObjectToBuffer (DataType *Destination, DataType *Src,
1639 		    int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1640 {
1641   /* setup local identifiers used by Add operations */
1642   Dest = Destination;
1643   Source = Src;
1644   return (ObjectOperation (&AddBufferFunctions, Type, Ptr1, Ptr2, Ptr3));
1645 }
1646 
1647 /* ---------------------------------------------------------------------- */
1648 
1649 HID_Action rotate_action_list[] = {
1650   {"FreeRotateBuffer", 0, ActionFreeRotateBuffer,
1651    freerotatebuffer_syntax, freerotatebuffer_help},
1652   {"LoadFootprint", 0, LoadFootprint,
1653    loadfootprint_syntax, loadfootprint_help}
1654 };
1655 
1656 REGISTER_ACTIONS (rotate_action_list)
1657