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