1 /*!
2  * \file src/draw.c
3  *
4  * \brief Drawing routines.
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, 2003, 2004 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 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 
37 #include "global.h"
38 #include "hid_draw.h"
39 
40 /*#include "clip.h"*/
41 #include "compat.h"
42 #include "crosshair.h"
43 #include "data.h"
44 #include "draw.h"
45 #include "error.h"
46 #include "mymem.h"
47 #include "misc.h"
48 #include "rotate.h"
49 #include "rtree.h"
50 #include "search.h"
51 #include "select.h"
52 #include "print.h"
53 
54 #ifdef HAVE_LIBDMALLOC
55 #include <dmalloc.h>
56 #endif
57 
58 #undef NDEBUG
59 #include <assert.h>
60 
61 #ifndef MAXINT
62 #define MAXINT (((unsigned int)(~0))>>1)
63 #endif
64 
65 #define	SMALL_SMALL_TEXT_SIZE	0
66 #define	SMALL_TEXT_SIZE			1
67 #define	NORMAL_TEXT_SIZE		2
68 #define	LARGE_TEXT_SIZE			3
69 #define	N_TEXT_SIZES			4
70 
71 
72 /* ---------------------------------------------------------------------------
73  * some local identifiers
74  */
75 static BoxType Block = {MAXINT, MAXINT, -MAXINT, -MAXINT};
76 
77 static int doing_pinout = 0;
78 static bool doing_assy = false;
79 
80 static int current_layergroup; /* used by via_callback */
81 
82 /* ---------------------------------------------------------------------------
83  * some local prototypes
84  */
85 static void DrawEverything (const BoxType *);
86 static void DrawPPV (int group, const BoxType *);
87 static void AddPart (void *);
88 static void DrawEMark (ElementType *, Coord, Coord, bool);
89 static void DrawRats (const BoxType *);
90 
91 static void
set_object_color(AnyObjectType * obj,char * warn_color,char * selected_color,char * connected_color,char * found_color,char * normal_color)92 set_object_color (AnyObjectType *obj, char *warn_color, char *selected_color,
93                   char *connected_color, char *found_color, char *normal_color)
94 {
95   char *color;
96 
97   if      (warn_color      != NULL && TEST_FLAG (WARNFLAG,      obj)) color = warn_color;
98   else if (selected_color  != NULL && TEST_FLAG (SELECTEDFLAG,  obj)) color = selected_color;
99   else if (connected_color != NULL && TEST_FLAG (CONNECTEDFLAG, obj)) color = connected_color;
100   else if (found_color     != NULL && TEST_FLAG (FOUNDFLAG,     obj)) color = found_color;
101   else                                                                color = normal_color;
102 
103   gui->graphics->set_color (Output.fgGC, color);
104 }
105 
106 static void
set_layer_object_color(LayerType * layer,AnyObjectType * obj)107 set_layer_object_color (LayerType *layer, AnyObjectType *obj)
108 {
109   set_object_color (obj, NULL, layer->SelectedColor, PCB->ConnectedColor, PCB->FoundColor, layer->Color);
110 }
111 
112 /*!
113  * \brief Adds the update rect to the update region.
114  */
115 static void
AddPart(void * b)116 AddPart (void *b)
117 {
118   BoxType *box = (BoxType *) b;
119 
120   Block.X1 = MIN (Block.X1, box->X1);
121   Block.X2 = MAX (Block.X2, box->X2);
122   Block.Y1 = MIN (Block.Y1, box->Y1);
123   Block.Y2 = MAX (Block.Y2, box->Y2);
124 }
125 
126 /*!
127  * \brief Initiate the actual redrawing of the updated area.
128  */
129 void
Draw(void)130 Draw (void)
131 {
132   if (Block.X1 <= Block.X2 && Block.Y1 <= Block.Y2)
133     gui->invalidate_lr (Block.X1, Block.X2, Block.Y1, Block.Y2);
134 
135   /* shrink the update block */
136   Block.X1 = Block.Y1 =  MAXINT;
137   Block.X2 = Block.Y2 = -MAXINT;
138 }
139 
140 /*!
141  * \brief Redraws all the data by the event handlers.
142  */
143 void
Redraw(void)144 Redraw (void)
145 {
146   gui->invalidate_all ();
147 }
148 
149 static void
_draw_pv_name(PinType * pv)150 _draw_pv_name (PinType *pv)
151 {
152   BoxType box;
153   bool vert;
154   TextType text;
155 
156   if (!pv->Name || !pv->Name[0])
157     text.TextString = EMPTY (pv->Number);
158   else
159     text.TextString = EMPTY (TEST_FLAG (SHOWNUMBERFLAG, PCB) ? pv->Number : pv->Name);
160 
161   vert = TEST_FLAG (EDGE2FLAG, pv);
162 
163   if (vert)
164     {
165       box.X1 = pv->X - pv->Thickness    / 2 + Settings.PinoutTextOffsetY;
166       box.Y1 = pv->Y - pv->DrillingHole / 2 - Settings.PinoutTextOffsetX;
167     }
168   else
169     {
170       box.X1 = pv->X + pv->DrillingHole / 2 + Settings.PinoutTextOffsetX;
171       box.Y1 = pv->Y - pv->Thickness    / 2 + Settings.PinoutTextOffsetY;
172     }
173 
174   gui->graphics->set_color (Output.fgGC, PCB->PinNameColor);
175 
176   text.Flags = NoFlags ();
177   /* Set font height to approx 56% of pin thickness */
178   text.Scale = 56 * pv->Thickness / FONT_CAPHEIGHT;
179   text.X = box.X1;
180   text.Y = box.Y1;
181   text.Direction = vert ? 1 : 0;
182 
183   if (gui->gui)
184     doing_pinout++;
185   gui->graphics->draw_pcb_text (Output.fgGC, &text, 0);
186   if (gui->gui)
187     doing_pinout--;
188 }
189 
190 static void
_draw_pv(PinType * pv,bool draw_hole)191 _draw_pv (PinType *pv, bool draw_hole)
192 {
193   if (TEST_FLAG (THINDRAWFLAG, PCB))
194     gui->graphics->thindraw_pcb_pv (Output.fgGC, Output.fgGC, pv, draw_hole, false);
195   else if (!ViaIsOnAnyVisibleLayer (pv))
196     gui->graphics->thindraw_pcb_pv (Output.fgGC, Output.fgGC, pv, false, false);
197   else
198     {
199       gui->graphics->fill_pcb_pv (Output.fgGC, Output.bgGC, pv, draw_hole, false);
200       if (gui->gui
201           && VIA_IS_BURIED (pv)
202           && !(TEST_FLAG (SELECTEDFLAG,  pv)
203 	       || TEST_FLAG (CONNECTEDFLAG, pv)
204 	       || TEST_FLAG (FOUNDFLAG,     pv)))
205         {
206           int w = (pv->Thickness - pv->DrillingHole) / 4;
207 	  int r = pv->DrillingHole / 2 + w  / 2;
208           gui->graphics->set_line_cap (Output.fgGC, Square_Cap);
209 	  gui->graphics->set_color (Output.fgGC, PCB->Data->Layer[pv->BuriedFrom].Color);
210           gui->graphics->set_line_width (Output.fgGC, w);
211           gui->graphics->draw_arc (Output.fgGC, pv->X, pv->Y, r, r, 270, 180);
212 	  gui->graphics->set_color (Output.fgGC, PCB->Data->Layer[pv->BuriedTo].Color);
213           gui->graphics->set_line_width (Output.fgGC, w);
214           gui->graphics->draw_arc (Output.fgGC, pv->X, pv->Y, r, r, 90, 180);
215 	}
216     }
217 
218   if ((!TEST_FLAG (HOLEFLAG, pv) && TEST_FLAG (DISPLAYNAMEFLAG, pv)) || doing_pinout)
219     _draw_pv_name (pv);
220 }
221 
222 static void
draw_pin(PinType * pin,bool draw_hole)223 draw_pin (PinType *pin, bool draw_hole)
224 {
225   if (doing_pinout)
226     gui->graphics->set_color (Output.fgGC, PCB->PinColor);
227   else
228     set_object_color ((AnyObjectType *)pin,
229                       PCB->WarnColor, PCB->PinSelectedColor,
230                       PCB->ConnectedColor, PCB->FoundColor, PCB->PinColor);
231 
232   _draw_pv (pin, draw_hole);
233 }
234 
235 static int
pin_callback(const BoxType * b,void * cl)236 pin_callback (const BoxType * b, void *cl)
237 {
238   draw_pin ((PinType *)b, false);
239   return 1;
240 }
241 
242 static void
draw_via(PinType * via,bool draw_hole)243 draw_via (PinType *via, bool draw_hole)
244 {
245   if (doing_pinout)
246     gui->graphics->set_color (Output.fgGC, PCB->ViaColor);
247   else
248     set_object_color ((AnyObjectType *)via,
249                       PCB->WarnColor, PCB->ViaSelectedColor,
250                       PCB->ConnectedColor, PCB->FoundColor, PCB->ViaColor);
251 
252   _draw_pv (via, draw_hole);
253 }
254 
255 static bool
via_visible_on_layer_group(PinType * via)256 via_visible_on_layer_group (PinType *via)
257 {
258   if (current_layergroup == -1)
259      return true;
260   else
261    return ViaIsOnLayerGroup (via, current_layergroup);
262 }
263 
264 static int
via_callback(const BoxType * b,void * cl)265 via_callback (const BoxType * b, void *cl)
266 {
267   PinType *via = (PinType *)b;
268 
269   if (via_visible_on_layer_group (via))
270     draw_via (via, false);
271 
272   return 1;
273 }
274 
275 static void
draw_pad_name(PadType * pad)276 draw_pad_name (PadType *pad)
277 {
278   BoxType box;
279   bool vert;
280   TextType text;
281 
282   if (!pad->Name || !pad->Name[0])
283     text.TextString = EMPTY (pad->Number);
284   else
285     text.TextString = EMPTY (TEST_FLAG (SHOWNUMBERFLAG, PCB) ? pad->Number : pad->Name);
286 
287   /* should text be vertical ? */
288   vert = (pad->Point1.X == pad->Point2.X);
289 
290   if (vert)
291     {
292       box.X1 = pad->Point1.X                      - pad->Thickness / 2;
293       box.Y1 = MAX (pad->Point1.Y, pad->Point2.Y) + pad->Thickness / 2;
294       box.X1 += Settings.PinoutTextOffsetY;
295       box.Y1 -= Settings.PinoutTextOffsetX;
296     }
297   else
298     {
299       box.X1 = MIN (pad->Point1.X, pad->Point2.X) - pad->Thickness / 2;
300       box.Y1 = pad->Point1.Y                      - pad->Thickness / 2;
301       box.X1 += Settings.PinoutTextOffsetX;
302       box.Y1 += Settings.PinoutTextOffsetY;
303     }
304 
305   gui->graphics->set_color (Output.fgGC, PCB->PinNameColor);
306 
307   text.Flags = NoFlags ();
308   /* Set font height to approx 90% of pin thickness */
309   text.Scale = 90 * pad->Thickness / FONT_CAPHEIGHT;
310   text.X = box.X1;
311   text.Y = box.Y1;
312   text.Direction = vert ? 1 : 0;
313 
314   gui->graphics->draw_pcb_text (Output.fgGC, &text, 0);
315 }
316 
317 static void
_draw_pad(hidGC gc,PadType * pad,bool clear,bool mask)318 _draw_pad (hidGC gc, PadType *pad, bool clear, bool mask)
319 {
320   if (clear && !mask && pad->Clearance <= 0)
321     return;
322 
323   if (TEST_FLAG (THINDRAWFLAG, PCB) ||
324       (clear && TEST_FLAG (THINDRAWPOLYFLAG, PCB)))
325     gui->graphics->thindraw_pcb_pad (gc, pad, clear, mask);
326   else
327     gui->graphics->fill_pcb_pad (gc, pad, clear, mask);
328 }
329 
330 static void
draw_pad(PadType * pad)331 draw_pad (PadType *pad)
332 {
333   if (doing_pinout)
334     gui->graphics->set_color (Output.fgGC, PCB->PinColor);
335   else
336     set_object_color ((AnyObjectType *)pad, PCB->WarnColor,
337                       PCB->PinSelectedColor, PCB->ConnectedColor, PCB->FoundColor,
338                       FRONT (pad) ? PCB->PinColor : PCB->InvisibleObjectsColor);
339 
340   _draw_pad (Output.fgGC, pad, false, false);
341 
342   if (doing_pinout || TEST_FLAG (DISPLAYNAMEFLAG, pad))
343     draw_pad_name (pad);
344 }
345 
346 static int
pad_callback(const BoxType * b,void * cl)347 pad_callback (const BoxType * b, void *cl)
348 {
349   PadType *pad = (PadType *) b;
350   int *side = cl;
351 
352   if (ON_SIDE (pad, *side))
353     draw_pad (pad);
354   return 1;
355 }
356 
357 static void
draw_element_name(ElementType * element)358 draw_element_name (ElementType *element)
359 {
360   if ((TEST_FLAG (HIDENAMESFLAG, PCB) && gui->gui) ||
361       TEST_FLAG (HIDENAMEFLAG, element))
362     return;
363   if (doing_pinout || doing_assy)
364     gui->graphics->set_color (Output.fgGC, PCB->ElementColor);
365   else if (TEST_FLAG (SELECTEDFLAG, &ELEMENT_TEXT (PCB, element)))
366     gui->graphics->set_color (Output.fgGC, PCB->ElementSelectedColor);
367   else if (FRONT (element))
368     gui->graphics->set_color (Output.fgGC, PCB->ElementColor);
369   else
370     gui->graphics->set_color (Output.fgGC, PCB->InvisibleObjectsColor);
371   gui->graphics->draw_pcb_text (Output.fgGC, &ELEMENT_TEXT (PCB, element), PCB->minSlk);
372 }
373 
374 static int
name_callback(const BoxType * b,void * cl)375 name_callback (const BoxType * b, void *cl)
376 {
377   TextType *text = (TextType *) b;
378   ElementType *element = (ElementType *) text->Element;
379   int *side = cl;
380 
381   if (TEST_FLAG (HIDENAMEFLAG, element))
382     return 0;
383 
384   if (ON_SIDE (element, *side))
385     draw_element_name (element);
386   return 0;
387 }
388 
389 static void
draw_element_pins_and_pads(ElementType * element)390 draw_element_pins_and_pads (ElementType *element)
391 {
392   PAD_LOOP (element);
393   {
394     if (doing_pinout || doing_assy || FRONT (pad) || PCB->InvisibleObjectsOn)
395       draw_pad (pad);
396   }
397   END_LOOP;
398   PIN_LOOP (element);
399   {
400     draw_pin (pin, true);
401   }
402   END_LOOP;
403 }
404 
405 static int
EMark_callback(const BoxType * b,void * cl)406 EMark_callback (const BoxType * b, void *cl)
407 {
408   ElementType *element = (ElementType *) b;
409 
410   DrawEMark (element, element->MarkX, element->MarkY, !FRONT (element));
411   return 1;
412 }
413 
414 typedef struct
415 {
416   int plated;
417   bool drill_pair;
418   Cardinal group_from;
419   Cardinal group_to;
420 } hole_info;
421 
422 static int
hole_callback(const BoxType * b,void * cl)423 hole_callback (const BoxType * b, void *cl)
424 {
425   hole_info his = {-1, false, 0, 0};
426   hole_info *hi = &his;
427   PinType *pv = (PinType *) b;
428 
429   if (cl)
430     hi = (hole_info *)cl;
431 
432   if (hi->drill_pair)
433     {
434       if (hi->group_from != 0
435           || hi->group_to != 0)
436 	{
437           if (VIA_IS_BURIED (pv))
438             {
439               if (hi->group_from == GetLayerGroupNumberByNumber (pv->BuriedFrom)
440                   && hi->group_to == GetLayerGroupNumberByNumber (pv->BuriedTo))
441 	        goto via_ok;
442 	    }
443 	}
444       else
445         if (!VIA_IS_BURIED (pv))
446 	  goto via_ok;
447 
448       return 1;
449     }
450 
451 via_ok:
452   if ((hi->plated == 0 && !TEST_FLAG (HOLEFLAG, pv)) ||
453       (hi->plated == 1 &&  TEST_FLAG (HOLEFLAG, pv)))
454     return 1;
455 
456   if (!via_visible_on_layer_group (pv))
457      return 1;
458 
459   if (TEST_FLAG (THINDRAWFLAG, PCB))
460     {
461       if (!TEST_FLAG (HOLEFLAG, pv))
462         {
463           gui->graphics->set_line_cap (Output.fgGC, Round_Cap);
464           gui->graphics->set_line_width (Output.fgGC, 0);
465           gui->graphics->draw_arc (Output.fgGC,
466                                    pv->X, pv->Y, pv->DrillingHole / 2,
467                                    pv->DrillingHole / 2, 0, 360);
468         }
469     }
470   else
471     if (ViaIsOnAnyVisibleLayer (pv))
472       gui->graphics->fill_circle (Output.bgGC, pv->X, pv->Y, pv->DrillingHole / 2);
473     else
474       {
475           gui->graphics->set_line_cap (Output.fgGC, Round_Cap);
476           gui->graphics->set_line_width (Output.fgGC, 0);
477           gui->graphics->draw_arc (Output.fgGC,
478                                    pv->X, pv->Y, pv->DrillingHole / 2,
479                                    pv->DrillingHole / 2, 0, 360);
480       }
481 
482   if (TEST_FLAG (HOLEFLAG, pv))
483     {
484       set_object_color ((AnyObjectType *) pv,
485                         PCB->WarnColor, PCB->ViaSelectedColor,
486                         NULL, NULL, Settings.BlackColor);
487 
488       gui->graphics->set_line_cap (Output.fgGC, Round_Cap);
489       gui->graphics->set_line_width (Output.fgGC, 0);
490       gui->graphics->draw_arc (Output.fgGC,
491                                pv->X, pv->Y, pv->DrillingHole / 2,
492                                pv->DrillingHole / 2, 0, 360);
493     }
494   return 1;
495 }
496 
497 void
DrawHoles(bool draw_plated,bool draw_unplated,const BoxType * drawn_area,Cardinal g_from,Cardinal g_to)498 DrawHoles (bool draw_plated, bool draw_unplated, const BoxType *drawn_area, Cardinal g_from, Cardinal g_to)
499 {
500   hole_info hi = {-1, true, g_from, g_to};
501 
502   if ( draw_plated && !draw_unplated) hi.plated = 1;
503   if (!draw_plated &&  draw_unplated) hi.plated = 0;
504 
505   current_layergroup = -1;
506 
507   r_search (PCB->Data->pin_tree, drawn_area, NULL, hole_callback, &hi);
508   r_search (PCB->Data->via_tree, drawn_area, NULL, hole_callback, &hi);
509 }
510 
511 static int
line_callback(const BoxType * b,void * cl)512 line_callback (const BoxType * b, void *cl)
513 {
514   LayerType *layer = (LayerType *) cl;
515   LineType *line = (LineType *) b;
516 
517   set_layer_object_color (layer, (AnyObjectType *) line);
518   gui->graphics->draw_pcb_line (Output.fgGC, line);
519 
520   return 1;
521 }
522 
523 static int
rat_callback(const BoxType * b,void * cl)524 rat_callback (const BoxType * b, void *cl)
525 {
526   RatType *rat = (RatType *)b;
527 
528   set_object_color ((AnyObjectType *) rat, NULL, PCB->RatSelectedColor,
529                     PCB->ConnectedColor, PCB->FoundColor, PCB->RatColor);
530 
531   if (Settings.RatThickness < 100)
532     rat->Thickness = pixel_slop * Settings.RatThickness;
533   /* rats.c set VIAFLAG if this rat goes to a containing poly: draw a donut */
534   if (TEST_FLAG(VIAFLAG, rat))
535     {
536       int w = rat->Thickness;
537 
538       if (TEST_FLAG (THINDRAWFLAG, PCB))
539         gui->graphics->set_line_width (Output.fgGC, 0);
540       else
541         gui->graphics->set_line_width (Output.fgGC, w);
542       gui->graphics->draw_arc (Output.fgGC, rat->Point1.X, rat->Point1.Y,
543                                w * 2, w * 2, 0, 360);
544     }
545   else
546     gui->graphics->draw_pcb_line (Output.fgGC, (LineType *) rat);
547   return 1;
548 }
549 
550 static int
arc_callback(const BoxType * b,void * cl)551 arc_callback (const BoxType * b, void *cl)
552 {
553   LayerType *layer = (LayerType *) cl;
554   ArcType *arc =  (ArcType *) b;
555 
556   set_layer_object_color (layer, (AnyObjectType *) arc);
557   gui->graphics->draw_pcb_arc (Output.fgGC, arc);
558 
559   return 1;
560 }
561 
562 static void
draw_element_package(ElementType * element)563 draw_element_package (ElementType *element)
564 {
565   /* set color and draw lines, arcs, text and pins */
566   if (doing_pinout || doing_assy)
567     gui->graphics->set_color (Output.fgGC, PCB->ElementColor);
568   else if (TEST_FLAG (SELECTEDFLAG, element))
569     gui->graphics->set_color (Output.fgGC, PCB->ElementSelectedColor);
570   else if (FRONT (element))
571     gui->graphics->set_color (Output.fgGC, PCB->ElementColor);
572   else
573     gui->graphics->set_color (Output.fgGC, PCB->InvisibleObjectsColor);
574 
575   /* draw lines, arcs, text and pins */
576   ELEMENTLINE_LOOP (element);
577   {
578     gui->graphics->draw_pcb_line (Output.fgGC, line);
579   }
580   END_LOOP;
581   ARC_LOOP (element);
582   {
583     gui->graphics->draw_pcb_arc (Output.fgGC, arc);
584   }
585   END_LOOP;
586 }
587 
588 static int
element_callback(const BoxType * b,void * cl)589 element_callback (const BoxType * b, void *cl)
590 {
591   ElementType *element = (ElementType *) b;
592   int *side = cl;
593 
594   if (ON_SIDE (element, *side))
595     draw_element_package (element);
596   return 1;
597 }
598 
599 /*!
600  * \brief Prints assembly drawing.
601  */
602 void
PrintAssembly(int side,const BoxType * drawn_area)603 PrintAssembly (int side, const BoxType * drawn_area)
604 {
605   int side_group = GetLayerGroupNumberBySide (side);
606 
607   doing_assy = true;
608   gui->graphics->set_draw_faded (Output.fgGC, 1);
609   DrawLayerGroup (side_group, drawn_area);
610   gui->graphics->set_draw_faded (Output.fgGC, 0);
611 
612   /* draw package */
613   DrawSilk (side, drawn_area);
614   doing_assy = false;
615 }
616 
617 /*!
618  * \brief Initializes some identifiers for a new zoom factor and redraws
619  * whole screen.
620  */
621 static void
DrawEverything(const BoxType * drawn_area)622 DrawEverything (const BoxType *drawn_area)
623 {
624   int i, ngroups, side;
625   int top_group, bottom_group;
626   /* This is the list of layer groups we will draw.  */
627   int do_group[MAX_GROUP];
628   /* This is the reverse of the order in which we draw them.  */
629   int drawn_groups[MAX_GROUP];
630   int plated, unplated;
631   bool paste_empty;
632   int g_from, g_to;
633   char s[22];
634 
635   PCB->Data->SILKLAYER.Color = PCB->ElementColor;
636   PCB->Data->BACKSILKLAYER.Color = PCB->InvisibleObjectsColor;
637 
638   memset (do_group, 0, sizeof (do_group));
639   for (ngroups = 0, i = 0; i < max_copper_layer; i++)
640     {
641       LayerType *l = LAYER_ON_STACK (i);
642       int group = GetLayerGroupNumberByNumber (LayerStack[i]);
643       if (l->On && !do_group[group])
644 	{
645 	  do_group[group] = 1;
646 	  drawn_groups[ngroups++] = group;
647 	}
648     }
649 
650   top_group = GetLayerGroupNumberBySide (TOP_SIDE);
651   bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
652 
653   /*
654    * first draw all 'invisible' stuff
655    */
656   if (!TEST_FLAG (CHECKPLANESFLAG, PCB)
657       && gui->set_layer ("invisible", SL (INVISIBLE, 0), 0))
658     {
659       side = SWAP_IDENT ? TOP_SIDE : BOTTOM_SIDE;
660       if (PCB->ElementOn)
661 	{
662 	  r_search (PCB->Data->element_tree, drawn_area, NULL, element_callback, &side);
663 	  r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], drawn_area, NULL, name_callback, &side);
664 	  DrawLayer (&(PCB->Data->Layer[max_copper_layer + side]), drawn_area);
665 	}
666       r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side);
667       gui->end_layer ();
668     }
669 
670   /* draw all layers in layerstack order */
671   for (i = ngroups - 1; i >= 0; i--)
672     {
673       int group = drawn_groups[i];
674 
675       if (gui->set_layer (0, group, 0))
676         {
677           DrawLayerGroup (group, drawn_area);
678           gui->end_layer ();
679         }
680     }
681 
682   if (TEST_FLAG (CHECKPLANESFLAG, PCB) && gui->gui)
683     return;
684 
685   /* Draw pins, pads, vias below silk */
686   if (gui->gui)
687     DrawPPV (SWAP_IDENT ? bottom_group : top_group, drawn_area);
688   else
689     {
690       CountHoles (&plated, &unplated, drawn_area);
691 
692       if (plated && gui->set_layer ("plated-drill", SL (PDRILL, 0), 0))
693         {
694           DrawHoles (true, false, drawn_area, 0, 0);
695           gui->end_layer ();
696         }
697 
698       if (unplated && gui->set_layer ("unplated-drill", SL (UDRILL, 0), 0))
699         {
700           DrawHoles (false, true, drawn_area, 0, 0);
701           gui->end_layer ();
702         }
703 
704       for (g_from = 0; g_from < (max_group - 1); g_from++)
705         for (g_to = g_from+1 ; g_to < max_group; g_to++ )
706 	  {
707             CountHolesEx (&plated, &unplated, drawn_area, g_from, g_to);
708 	    sprintf (s, "plated-drill_%02d-%02d", g_from+1, g_to+1);
709             if (plated && gui->set_layer (s, SL (PDRILL, 0), 0))
710               {
711                 DrawHoles (true, false, drawn_area, g_from, g_to);
712                 gui->end_layer ();
713               }
714 
715 	    sprintf (s, "unplated-drill_%02d-%02d", g_from+1, g_to+1);
716             if (unplated && gui->set_layer (s, SL (UDRILL, 0), 0))
717               {
718                 DrawHoles (false, true, drawn_area, g_from, g_to);
719                 gui->end_layer ();
720               }
721 	  }
722 
723 
724     }
725 
726   /* Draw the solder mask if turned on */
727   if (gui->set_layer ("componentmask", SL (MASK, TOP), 0))
728     {
729       DrawMask (TOP_SIDE, drawn_area);
730       gui->end_layer ();
731     }
732 
733   if (gui->set_layer ("soldermask", SL (MASK, BOTTOM), 0))
734     {
735       DrawMask (BOTTOM_SIDE, drawn_area);
736       gui->end_layer ();
737     }
738 
739   if (gui->set_layer ("topsilk", SL (SILK, TOP), 0))
740     {
741       DrawSilk (TOP_SIDE, drawn_area);
742       gui->end_layer ();
743     }
744 
745   if (gui->set_layer ("bottomsilk", SL (SILK, BOTTOM), 0))
746     {
747       DrawSilk (BOTTOM_SIDE, drawn_area);
748       gui->end_layer ();
749     }
750 
751   if (gui->gui)
752     {
753       /* Draw element Marks */
754       if (PCB->PinOn)
755 	r_search (PCB->Data->element_tree, drawn_area, NULL, EMark_callback,
756 		  NULL);
757       /* Draw rat lines on top */
758       if (gui->set_layer ("rats", SL (RATS, 0), 0))
759         {
760           DrawRats(drawn_area);
761           gui->end_layer ();
762         }
763     }
764 
765   paste_empty = IsPasteEmpty (TOP_SIDE);
766   if (gui->set_layer ("toppaste", SL (PASTE, TOP), paste_empty))
767     {
768       DrawPaste (TOP_SIDE, drawn_area);
769       gui->end_layer ();
770     }
771 
772   paste_empty = IsPasteEmpty (BOTTOM_SIDE);
773   if (gui->set_layer ("bottompaste", SL (PASTE, BOTTOM), paste_empty))
774     {
775       DrawPaste (BOTTOM_SIDE, drawn_area);
776       gui->end_layer ();
777     }
778 
779   if (gui->set_layer ("topassembly", SL (ASSY, TOP), 0))
780     {
781       PrintAssembly (TOP_SIDE, drawn_area);
782       gui->end_layer ();
783     }
784 
785   if (gui->set_layer ("bottomassembly", SL (ASSY, BOTTOM), 0))
786     {
787       PrintAssembly (BOTTOM_SIDE, drawn_area);
788       gui->end_layer ();
789     }
790 
791   if (gui->set_layer ("fab", SL (FAB, 0), 0))
792     {
793       PrintFab (Output.fgGC);
794       gui->end_layer ();
795     }
796 }
797 
798 static void
DrawEMark(ElementType * e,Coord X,Coord Y,bool invisible)799 DrawEMark (ElementType *e, Coord X, Coord Y, bool invisible)
800 {
801   Coord mark_size = EMARK_SIZE;
802   if (!PCB->InvisibleObjectsOn && invisible)
803     return;
804 
805   if (e->Pin != NULL)
806     {
807       PinType *pin0 = e->Pin->data;
808       if (TEST_FLAG (HOLEFLAG, pin0))
809 	mark_size = MIN (mark_size, pin0->DrillingHole / 2);
810       else
811 	mark_size = MIN (mark_size, pin0->Thickness / 2);
812     }
813 
814   if (e->Pad != NULL)
815     {
816       PadType *pad0 = e->Pad->data;
817       mark_size = MIN (mark_size, pad0->Thickness / 2);
818     }
819 
820   gui->graphics->set_color (Output.fgGC,
821 		  invisible ? PCB->InvisibleMarkColor : PCB->ElementColor);
822   gui->graphics->set_line_cap (Output.fgGC, Trace_Cap);
823   gui->graphics->set_line_width (Output.fgGC, 0);
824   gui->graphics->draw_line (Output.fgGC, X - mark_size, Y, X, Y - mark_size);
825   gui->graphics->draw_line (Output.fgGC, X + mark_size, Y, X, Y - mark_size);
826   gui->graphics->draw_line (Output.fgGC, X - mark_size, Y, X, Y + mark_size);
827   gui->graphics->draw_line (Output.fgGC, X + mark_size, Y, X, Y + mark_size);
828 
829   /*
830    * If an element is locked, place a "L" on top of the "diamond".
831    * This provides a nice visual indication that it is locked that
832    * works even for color blind users.
833    */
834   if (TEST_FLAG (LOCKFLAG, e) )
835     {
836       gui->graphics->draw_line (Output.fgGC, X, Y, X + 2 * mark_size, Y);
837       gui->graphics->draw_line (Output.fgGC, X, Y, X, Y - 4* mark_size);
838     }
839 }
840 
841 /*!
842  * \brief Draws pins pads and vias - Always draws for non-gui HIDs,
843  * otherwise drawing depends on PCB->PinOn and PCB->ViaOn.
844  */
845 static void
DrawPPV(int group,const BoxType * drawn_area)846 DrawPPV (int group, const BoxType *drawn_area)
847 {
848   int top_group = GetLayerGroupNumberBySide (TOP_SIDE);
849   int bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
850   int side;
851 
852   if (PCB->PinOn || !gui->gui)
853     {
854       /* draw element pins */
855       r_search (PCB->Data->pin_tree, drawn_area, NULL, pin_callback, NULL);
856 
857       /* draw element pads */
858       if (group == top_group)
859         {
860           side = TOP_SIDE;
861           r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side);
862         }
863 
864       if (group == bottom_group)
865         {
866           side = BOTTOM_SIDE;
867           r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side);
868         }
869     }
870 
871   /* draw vias */
872   if (PCB->ViaOn || !gui->gui)
873     {
874 
875       current_layergroup = (gui->gui)?(-1):group; /* Limit vias only for layer group */
876 
877       r_search (PCB->Data->via_tree, drawn_area, NULL, via_callback, NULL);
878       r_search (PCB->Data->via_tree, drawn_area, NULL, hole_callback, NULL);
879     }
880   if (PCB->PinOn || doing_assy)
881     r_search (PCB->Data->pin_tree, drawn_area, NULL, hole_callback, NULL);
882 }
883 
884 static int
clearPin_callback(const BoxType * b,void * cl)885 clearPin_callback (const BoxType * b, void *cl)
886 {
887   PinType *pin = (PinType *) b;
888   bool do_clear=true;
889   int side;
890   if (TEST_FLAG (VIAFLAG, pin) && VIA_IS_BURIED (pin))
891     {
892       side=*((int*)cl);
893       if ((side == TOP_SIDE && pin->BuriedFrom != 0)
894           || (side == BOTTOM_SIDE && pin->BuriedTo != GetMaxBottomLayer ()))
895         do_clear = false;
896   }
897   if (do_clear)
898     {
899       if (TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG (THINDRAWPOLYFLAG, PCB))
900         gui->graphics->thindraw_pcb_pv (Output.pmGC, Output.pmGC, pin, false, true);
901       else
902         gui->graphics->fill_pcb_pv (Output.pmGC, Output.pmGC, pin, false, true);
903    }
904   return 1;
905 }
906 
907 struct poly_info {
908   const BoxType *drawn_area;
909   LayerType *layer;
910 };
911 
912 static int
poly_callback(const BoxType * b,void * cl)913 poly_callback (const BoxType * b, void *cl)
914 {
915   struct poly_info *i = cl;
916   PolygonType *polygon = (PolygonType *)b;
917 
918   set_layer_object_color (i->layer, (AnyObjectType *) polygon);
919 
920   gui->graphics->draw_pcb_polygon (Output.fgGC, polygon, i->drawn_area);
921 
922   return 1;
923 }
924 
925 static int
clearPad_callback(const BoxType * b,void * cl)926 clearPad_callback (const BoxType * b, void *cl)
927 {
928   PadType *pad = (PadType *) b;
929   int *side = cl;
930   if (ON_SIDE (pad, *side) && pad->Mask)
931     _draw_pad (Output.pmGC, pad, true, true);
932   return 1;
933 }
934 
935 /*!
936  * \brief Draws silk layer.
937  */
938 void
DrawSilk(int side,const BoxType * drawn_area)939 DrawSilk (int side, const BoxType * drawn_area)
940 {
941 #if 0
942   /* This code is used when you want to mask silk to avoid exposed
943      pins and pads.  We decided it was a bad idea to do this
944      unconditionally, but the code remains.  */
945 #endif
946 
947 #if 0
948   if (gui->poly_before)
949     {
950       gui->graphics->use_mask (HID_MASK_BEFORE);
951 #endif
952       DrawLayer (LAYER_PTR (max_copper_layer + side), drawn_area);
953       /* draw package */
954       r_search (PCB->Data->element_tree, drawn_area, NULL, element_callback, &side);
955       r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], drawn_area, NULL, name_callback, &side);
956 #if 0
957     }
958 
959   gui->graphics->use_mask (HID_MASK_CLEAR);
960   r_search (PCB->Data->pin_tree, drawn_area, NULL, clearPin_callback, NULL);
961   r_search (PCB->Data->via_tree, drawn_area, NULL, clearPin_callback, NULL);
962   r_search (PCB->Data->pad_tree, drawn_area, NULL, clearPad_callback, &side);
963 
964   if (gui->poly_after)
965     {
966       gui->graphics->use_mask (HID_MASK_AFTER);
967       DrawLayer (LAYER_PTR (max_copper_layer + layer), drawn_area);
968       /* draw package */
969       r_search (PCB->Data->element_tree, drawn_area, NULL, element_callback, &side);
970       r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], drawn_area, NULL, name_callback, &side);
971     }
972   gui->graphics->use_mask (HID_MASK_OFF);
973 #endif
974 }
975 
976 
977 static void
DrawMaskBoardArea(int mask_type,const BoxType * drawn_area)978 DrawMaskBoardArea (int mask_type, const BoxType *drawn_area)
979 {
980   /* Skip the mask drawing if the GUI doesn't want this type */
981   if ((mask_type == HID_MASK_BEFORE && !gui->poly_before) ||
982       (mask_type == HID_MASK_AFTER  && !gui->poly_after))
983     return;
984 
985   gui->graphics->use_mask (mask_type);
986   gui->graphics->set_color (Output.fgGC, PCB->MaskColor);
987   if (drawn_area == NULL)
988     gui->graphics->fill_rect (Output.fgGC, 0, 0, PCB->MaxWidth, PCB->MaxHeight);
989   else
990     gui->graphics->fill_rect (Output.fgGC, drawn_area->X1, drawn_area->Y1,
991                                            drawn_area->X2, drawn_area->Y2);
992 }
993 
994 /*!
995  * \brief Draws solder mask layer - this will cover nearly everything.
996  */
997 void
DrawMask(int side,const BoxType * screen)998 DrawMask (int side, const BoxType *screen)
999 {
1000   int thin = TEST_FLAG(THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB);
1001 
1002   if (thin)
1003     gui->graphics->set_color (Output.pmGC, PCB->MaskColor);
1004   else
1005     {
1006       DrawMaskBoardArea (HID_MASK_BEFORE, screen);
1007       gui->graphics->use_mask (HID_MASK_CLEAR);
1008     }
1009 
1010   r_search (PCB->Data->pin_tree, screen, NULL, clearPin_callback, NULL);
1011   r_search (PCB->Data->via_tree, screen, NULL, clearPin_callback, &side);
1012   r_search (PCB->Data->pad_tree, screen, NULL, clearPad_callback, &side);
1013 
1014   if (thin)
1015     gui->graphics->set_color (Output.pmGC, "erase");
1016   else
1017     {
1018       DrawMaskBoardArea (HID_MASK_AFTER, screen);
1019       gui->graphics->use_mask (HID_MASK_OFF);
1020     }
1021 }
1022 
1023 /*!
1024  * \brief Draws solder paste layer for a given side of the board.
1025  */
1026 void
DrawPaste(int side,const BoxType * drawn_area)1027 DrawPaste (int side, const BoxType *drawn_area)
1028 {
1029   gui->graphics->set_color (Output.fgGC, PCB->ElementColor);
1030   ALLPAD_LOOP (PCB->Data);
1031   {
1032     if (ON_SIDE (pad, side) && !TEST_FLAG (NOPASTEFLAG, pad) && pad->Mask > 0)
1033       {
1034         Coord save_thickness = pad->Thickness;
1035 	Coord save_mask = pad->Mask;
1036 
1037         if (Settings.PasteAdjust != 0)
1038 	{
1039 	  pad->Thickness = pad->Thickness + Settings.PasteAdjust;
1040 	  pad->Mask = pad->Mask + Settings.PasteAdjust;
1041 	  if (pad->Thickness < 0) {
1042 	  printf ("adjust thickness %8.4f -> %8.4f mask  %8.4f -> %8.4f\n",
1043 		  COORD_TO_MM(save_thickness), COORD_TO_MM(pad->Thickness),
1044 		  COORD_TO_MM(save_mask), COORD_TO_MM(pad->Mask));
1045 	    pad->Thickness = 0;
1046 	  }
1047 	  if (pad->Mask < 0)
1048 	    pad->Mask = 0;
1049 	}
1050         if (pad->Mask < pad->Thickness)
1051           _draw_pad (Output.fgGC, pad, true, true);
1052         else
1053           _draw_pad (Output.fgGC, pad, false, false);
1054         pad->Thickness = save_thickness;
1055 	pad->Mask = save_mask;
1056       }
1057   }
1058   ENDALL_LOOP;
1059 }
1060 
1061 static void
DrawRats(const BoxType * drawn_area)1062 DrawRats (const BoxType *drawn_area)
1063 {
1064   /*
1065    * XXX lesstif allows positive AND negative drawing in HID_MASK_CLEAR.
1066    * XXX gtk only allows negative drawing.
1067    * XXX using the mask here is to get rat transparency
1068    */
1069   int can_mask = strcmp(gui->name, "lesstif") == 0;
1070 
1071   if (can_mask)
1072     gui->graphics->use_mask (HID_MASK_CLEAR);
1073   r_search (PCB->Data->rat_tree, drawn_area, NULL, rat_callback, NULL);
1074   if (can_mask)
1075     gui->graphics->use_mask (HID_MASK_OFF);
1076 }
1077 
1078 static int
text_callback(const BoxType * b,void * cl)1079 text_callback (const BoxType * b, void *cl)
1080 {
1081   LayerType *layer = cl;
1082   TextType *text = (TextType *)b;
1083   int min_silk_line;
1084 
1085   if (TEST_FLAG (SELECTEDFLAG, text))
1086     gui->graphics->set_color (Output.fgGC, layer->SelectedColor);
1087   else
1088     gui->graphics->set_color (Output.fgGC, layer->Color);
1089   if (layer == &PCB->Data->SILKLAYER ||
1090       layer == &PCB->Data->BACKSILKLAYER)
1091     min_silk_line = PCB->minSlk;
1092   else
1093     min_silk_line = PCB->minWid;
1094   gui->graphics->draw_pcb_text (Output.fgGC, text, min_silk_line);
1095   return 1;
1096 }
1097 
1098 void
DrawLayer(LayerType * Layer,const BoxType * screen)1099 DrawLayer (LayerType *Layer, const BoxType *screen)
1100 {
1101   struct poly_info info = {screen, Layer};
1102 
1103   /* print the non-clearing polys */
1104   r_search (Layer->polygon_tree, screen, NULL, poly_callback, &info);
1105 
1106   if (TEST_FLAG (CHECKPLANESFLAG, PCB))
1107     return;
1108 
1109   /* draw all visible lines this layer */
1110   r_search (Layer->line_tree, screen, NULL, line_callback, Layer);
1111 
1112   /* draw the layer arcs on screen */
1113   r_search (Layer->arc_tree, screen, NULL, arc_callback, Layer);
1114 
1115   /* draw the layer text on screen */
1116   r_search (Layer->text_tree, screen, NULL, text_callback, Layer);
1117 
1118   /* We should check for gui->gui here, but it's kinda cool seeing the
1119      auto-outline magically disappear when you first add something to
1120      the "outline" layer.  */
1121   if (IsLayerEmpty (Layer)
1122       && (strcmp (Layer->Name, "outline") == 0
1123 	  || strcmp (Layer->Name, "route") == 0))
1124     {
1125       gui->graphics->set_color (Output.fgGC, Layer->Color);
1126       gui->graphics->set_line_width (Output.fgGC, PCB->minWid);
1127       gui->graphics->draw_rect (Output.fgGC,
1128                                 0, 0,
1129                                 PCB->MaxWidth, PCB->MaxHeight);
1130     }
1131 }
1132 
1133 /*!
1134  * \brief Draws one layer group.
1135  *
1136  * If the exporter is not a GUI, also draws the pins / pads / vias in
1137  * this layer group.
1138  */
1139 void
DrawLayerGroup(int group,const BoxType * drawn_area)1140 DrawLayerGroup (int group, const BoxType *drawn_area)
1141 {
1142   int i, rv = 1;
1143   int layernum;
1144   LayerType *Layer;
1145   int n_entries = PCB->LayerGroups.Number[group];
1146   Cardinal *layers = PCB->LayerGroups.Entries[group];
1147 
1148   for (i = n_entries - 1; i >= 0; i--)
1149     {
1150       layernum = layers[i];
1151       Layer = PCB->Data->Layer + layers[i];
1152       if (strcmp (Layer->Name, "outline") == 0 ||
1153           strcmp (Layer->Name, "route") == 0)
1154         rv = 0;
1155       if (layernum < max_copper_layer && Layer->On)
1156         DrawLayer (Layer, drawn_area);
1157     }
1158   if (n_entries > 1)
1159     rv = 1;
1160 
1161   if (rv && !gui->gui)
1162     DrawPPV (group, drawn_area);
1163 }
1164 
1165 static void
GatherPVName(PinType * Ptr)1166 GatherPVName (PinType *Ptr)
1167 {
1168   BoxType box;
1169   bool vert = TEST_FLAG (EDGE2FLAG, Ptr);
1170 
1171   if (vert)
1172     {
1173       box.X1 = Ptr->X - Ptr->Thickness / 2 + Settings.PinoutTextOffsetY;
1174       box.Y1 = Ptr->Y - Ptr->DrillingHole / 2 - Settings.PinoutTextOffsetX;
1175     }
1176   else
1177     {
1178       box.X1 = Ptr->X + Ptr->DrillingHole / 2 + Settings.PinoutTextOffsetX;
1179       box.Y1 = Ptr->Y - Ptr->Thickness / 2 + Settings.PinoutTextOffsetY;
1180     }
1181 
1182   if (vert)
1183     {
1184       box.X2 = box.X1;
1185       box.Y2 = box.Y1;
1186     }
1187   else
1188     {
1189       box.X2 = box.X1;
1190       box.Y2 = box.Y1;
1191     }
1192   AddPart (&box);
1193 }
1194 
1195 static void
GatherPadName(PadType * Pad)1196 GatherPadName (PadType *Pad)
1197 {
1198   BoxType box;
1199   bool vert;
1200 
1201   /* should text be vertical ? */
1202   vert = (Pad->Point1.X == Pad->Point2.X);
1203 
1204   if (vert)
1205     {
1206       box.X1 = Pad->Point1.X                      - Pad->Thickness / 2;
1207       box.Y1 = MAX (Pad->Point1.Y, Pad->Point2.Y) + Pad->Thickness / 2;
1208       box.X1 += Settings.PinoutTextOffsetY;
1209       box.Y1 -= Settings.PinoutTextOffsetX;
1210       box.X2 = box.X1;
1211       box.Y2 = box.Y1;
1212     }
1213   else
1214     {
1215       box.X1 = MIN (Pad->Point1.X, Pad->Point2.X) - Pad->Thickness / 2;
1216       box.Y1 = Pad->Point1.Y                      - Pad->Thickness / 2;
1217       box.X1 += Settings.PinoutTextOffsetX;
1218       box.Y1 += Settings.PinoutTextOffsetY;
1219       box.X2 = box.X1;
1220       box.Y2 = box.Y1;
1221     }
1222 
1223   AddPart (&box);
1224   return;
1225 }
1226 
1227 /*!
1228  * \brief Draw a via object.
1229  */
1230 void
DrawVia(PinType * Via)1231 DrawVia (PinType *Via)
1232 {
1233   AddPart (Via);
1234   if (!TEST_FLAG (HOLEFLAG, Via) && TEST_FLAG (DISPLAYNAMEFLAG, Via))
1235     DrawViaName (Via);
1236 }
1237 
1238 /*!
1239  * \brief Draws the name of a via.
1240  */
1241 void
DrawViaName(PinType * Via)1242 DrawViaName (PinType *Via)
1243 {
1244   GatherPVName (Via);
1245 }
1246 
1247 /*!
1248  * \brief Draw a pin object.
1249  */
1250 void
DrawPin(PinType * Pin)1251 DrawPin (PinType *Pin)
1252 {
1253   AddPart (Pin);
1254   if ((!TEST_FLAG (HOLEFLAG, Pin) && TEST_FLAG (DISPLAYNAMEFLAG, Pin))
1255       || doing_pinout)
1256     DrawPinName (Pin);
1257 }
1258 
1259 /*!
1260  * \brief Draws the name of a pin.
1261  */
1262 void
DrawPinName(PinType * Pin)1263 DrawPinName (PinType *Pin)
1264 {
1265   GatherPVName (Pin);
1266 }
1267 
1268 /*!
1269  * \brief Draw a pad object.
1270  */
1271 void
DrawPad(PadType * Pad)1272 DrawPad (PadType *Pad)
1273 {
1274   AddPart (Pad);
1275   if (doing_pinout || TEST_FLAG (DISPLAYNAMEFLAG, Pad))
1276     DrawPadName (Pad);
1277 }
1278 
1279 /*!
1280  * \brief Draws the name of a pad.
1281  */
1282 void
DrawPadName(PadType * Pad)1283 DrawPadName (PadType *Pad)
1284 {
1285   GatherPadName (Pad);
1286 }
1287 
1288 /*!
1289  * \brief Draws a line on a layer.
1290  */
1291 void
DrawLine(LayerType * Layer,LineType * Line)1292 DrawLine (LayerType *Layer, LineType *Line)
1293 {
1294   AddPart (Line);
1295 }
1296 
1297 /*!
1298  * \brief Draws a ratline.
1299  */
1300 void
DrawRat(RatType * Rat)1301 DrawRat (RatType *Rat)
1302 {
1303   if (Settings.RatThickness < 100)
1304     Rat->Thickness = pixel_slop * Settings.RatThickness;
1305   /* rats.c set VIAFLAG if this rat goes to a containing poly: draw a donut */
1306   if (TEST_FLAG(VIAFLAG, Rat))
1307     {
1308       Coord w = Rat->Thickness;
1309 
1310       BoxType b;
1311 
1312       b.X1 = Rat->Point1.X - w * 2 - w / 2;
1313       b.X2 = Rat->Point1.X + w * 2 + w / 2;
1314       b.Y1 = Rat->Point1.Y - w * 2 - w / 2;
1315       b.Y2 = Rat->Point1.Y + w * 2 + w / 2;
1316       AddPart (&b);
1317     }
1318   else
1319     DrawLine (NULL, (LineType *)Rat);
1320 }
1321 
1322 /*!
1323  * \brief Draws an arc on a layer.
1324  */
1325 void
DrawArc(LayerType * Layer,ArcType * Arc)1326 DrawArc (LayerType *Layer, ArcType *Arc)
1327 {
1328   AddPart (Arc);
1329 }
1330 
1331 /*!
1332  * \brief Draws a text on a layer.
1333  */
1334 void
DrawText(LayerType * Layer,TextType * Text)1335 DrawText (LayerType *Layer, TextType *Text)
1336 {
1337   AddPart (Text);
1338 }
1339 
1340 
1341 /*!
1342  * \brief Draws a polygon on a layer.
1343  */
1344 void
DrawPolygon(LayerType * Layer,PolygonType * Polygon)1345 DrawPolygon (LayerType *Layer, PolygonType *Polygon)
1346 {
1347   AddPart (Polygon);
1348 }
1349 
1350 /*!
1351  * \brief Draws an element.
1352  */
1353 void
DrawElement(ElementType * Element)1354 DrawElement (ElementType *Element)
1355 {
1356   DrawElementPackage (Element);
1357   DrawElementName (Element);
1358   DrawElementPinsAndPads (Element);
1359 }
1360 
1361 /*!
1362  * \brief Draws the name of an element.
1363  */
1364 void
DrawElementName(ElementType * Element)1365 DrawElementName (ElementType *Element)
1366 {
1367   if (TEST_FLAG (HIDENAMEFLAG, Element))
1368     return;
1369   DrawText (NULL, &ELEMENT_TEXT (PCB, Element));
1370 }
1371 
1372 /*!
1373  * \brief Draws the package of an element.
1374  */
1375 void
DrawElementPackage(ElementType * Element)1376 DrawElementPackage (ElementType *Element)
1377 {
1378   ELEMENTLINE_LOOP (Element);
1379   {
1380     DrawLine (NULL, line);
1381   }
1382   END_LOOP;
1383   ARC_LOOP (Element);
1384   {
1385     DrawArc (NULL, arc);
1386   }
1387   END_LOOP;
1388 }
1389 
1390 /*!
1391  * \brief Draw pins of an element.
1392  */
1393 void
DrawElementPinsAndPads(ElementType * Element)1394 DrawElementPinsAndPads (ElementType *Element)
1395 {
1396   PAD_LOOP (Element);
1397   {
1398     if (doing_pinout || doing_assy || FRONT (pad) || PCB->InvisibleObjectsOn)
1399       DrawPad (pad);
1400   }
1401   END_LOOP;
1402   PIN_LOOP (Element);
1403   {
1404     DrawPin (pin);
1405   }
1406   END_LOOP;
1407 }
1408 
1409 /*!
1410  * \brief Erase a via.
1411  */
1412 void
EraseVia(PinType * Via)1413 EraseVia (PinType *Via)
1414 {
1415   AddPart (Via);
1416   if (TEST_FLAG (DISPLAYNAMEFLAG, Via))
1417     EraseViaName (Via);
1418 }
1419 
1420 /*!
1421  * \brief Erase a ratline.
1422  */
1423 void
EraseRat(RatType * Rat)1424 EraseRat (RatType *Rat)
1425 {
1426   if (TEST_FLAG(VIAFLAG, Rat))
1427     {
1428       Coord w = Rat->Thickness;
1429 
1430       BoxType b;
1431 
1432       b.X1 = Rat->Point1.X - w * 2 - w / 2;
1433       b.X2 = Rat->Point1.X + w * 2 + w / 2;
1434       b.Y1 = Rat->Point1.Y - w * 2 - w / 2;
1435       b.Y2 = Rat->Point1.Y + w * 2 + w / 2;
1436       AddPart (&b);
1437     }
1438   else
1439     EraseLine ((LineType *)Rat);
1440 }
1441 
1442 
1443 /*!
1444  * \brief Erase a via name.
1445  */
1446 void
EraseViaName(PinType * Via)1447 EraseViaName (PinType *Via)
1448 {
1449   GatherPVName (Via);
1450 }
1451 
1452 /*!
1453  * \brief Erase a pad object.
1454  */
1455 void
ErasePad(PadType * Pad)1456 ErasePad (PadType *Pad)
1457 {
1458   AddPart (Pad);
1459   if (TEST_FLAG (DISPLAYNAMEFLAG, Pad))
1460     ErasePadName (Pad);
1461 }
1462 
1463 /*!
1464  * \brief Erase a pad name.
1465  */
1466 void
ErasePadName(PadType * Pad)1467 ErasePadName (PadType *Pad)
1468 {
1469   GatherPadName (Pad);
1470 }
1471 
1472 /*!
1473  * \brief Erase a pin object.
1474  */
1475 void
ErasePin(PinType * Pin)1476 ErasePin (PinType *Pin)
1477 {
1478   AddPart (Pin);
1479   if (TEST_FLAG (DISPLAYNAMEFLAG, Pin))
1480     ErasePinName (Pin);
1481 }
1482 
1483 /*!
1484  * \brief Erase a pin name.
1485  */
1486 void
ErasePinName(PinType * Pin)1487 ErasePinName (PinType *Pin)
1488 {
1489   GatherPVName (Pin);
1490 }
1491 
1492 /*!
1493  * \brief Erases a line on a layer.
1494  */
1495 void
EraseLine(LineType * Line)1496 EraseLine (LineType *Line)
1497 {
1498   AddPart (Line);
1499 }
1500 
1501 /*!
1502  * \brief Erases an arc on a layer.
1503  */
1504 void
EraseArc(ArcType * Arc)1505 EraseArc (ArcType *Arc)
1506 {
1507   if (!Arc->Thickness)
1508     return;
1509   AddPart (Arc);
1510 }
1511 
1512 /*!
1513  * \brief Erases a text on a layer.
1514  */
1515 void
EraseText(LayerType * Layer,TextType * Text)1516 EraseText (LayerType *Layer, TextType *Text)
1517 {
1518 /*  r_delete_entry (Layer->text_tree, (BoxType *) Text); */
1519   AddPart (Text);
1520 }
1521 
1522 /*!
1523  * \brief Erases a polygon on a layer.
1524  */
1525 void
ErasePolygon(PolygonType * Polygon)1526 ErasePolygon (PolygonType *Polygon)
1527 {
1528   AddPart (Polygon);
1529 }
1530 
1531 /*!
1532  * \brief Erases an element.
1533  */
1534 void
EraseElement(ElementType * Element)1535 EraseElement (ElementType *Element)
1536 {
1537   ELEMENTLINE_LOOP (Element);
1538   {
1539     EraseLine (line);
1540   }
1541   END_LOOP;
1542   ARC_LOOP (Element);
1543   {
1544     EraseArc (arc);
1545   }
1546   END_LOOP;
1547   EraseElementName (Element);
1548   EraseElementPinsAndPads (Element);
1549 }
1550 
1551 /*!
1552  * \brief Erases all pins and pads of an element.
1553  */
1554 void
EraseElementPinsAndPads(ElementType * Element)1555 EraseElementPinsAndPads (ElementType *Element)
1556 {
1557   PIN_LOOP (Element);
1558   {
1559     ErasePin (pin);
1560   }
1561   END_LOOP;
1562   PAD_LOOP (Element);
1563   {
1564     ErasePad (pad);
1565   }
1566   END_LOOP;
1567 }
1568 
1569 /*!
1570  * \brief Erases the name of an element.
1571  */
1572 void
EraseElementName(ElementType * Element)1573 EraseElementName (ElementType *Element)
1574 {
1575   if (TEST_FLAG (HIDENAMEFLAG, Element))
1576     return;
1577   EraseText (NULL, &ELEMENT_TEXT (PCB, Element));}
1578 
1579 
1580 void
EraseObject(int type,void * lptr,void * ptr)1581 EraseObject (int type, void *lptr, void *ptr)
1582 {
1583   switch (type)
1584     {
1585     case VIA_TYPE:
1586     case PIN_TYPE:
1587       ErasePin ((PinType *) ptr);
1588       break;
1589     case TEXT_TYPE:
1590       EraseText ((LayerType *)lptr, (TextType *) ptr);
1591       break;
1592     case ELEMENTNAME_TYPE:
1593       EraseElementName ((ElementType *) ptr);
1594       break;
1595     case POLYGON_TYPE:
1596       ErasePolygon ((PolygonType *) ptr);
1597       break;
1598     case ELEMENT_TYPE:
1599       EraseElement ((ElementType *) ptr);
1600       break;
1601     case LINE_TYPE:
1602     case ELEMENTLINE_TYPE:
1603     case RATLINE_TYPE:
1604       EraseLine ((LineType *) ptr);
1605       break;
1606     case PAD_TYPE:
1607       ErasePad ((PadType *) ptr);
1608       break;
1609     case ARC_TYPE:
1610     case ELEMENTARC_TYPE:
1611       EraseArc ((ArcType *) ptr);
1612       break;
1613     default:
1614       Message ("hace: Internal ERROR, trying to erase an unknown type\n");
1615     }
1616 }
1617 
1618 
1619 
1620 void
DrawObject(int type,void * ptr1,void * ptr2)1621 DrawObject (int type, void *ptr1, void *ptr2)
1622 {
1623   switch (type)
1624     {
1625     case VIA_TYPE:
1626       if (PCB->ViaOn)
1627 	DrawVia ((PinType *) ptr2);
1628       break;
1629     case LINE_TYPE:
1630       if (((LayerType *) ptr1)->On)
1631 	DrawLine ((LayerType *) ptr1, (LineType *) ptr2);
1632       break;
1633     case ARC_TYPE:
1634       if (((LayerType *) ptr1)->On)
1635 	DrawArc ((LayerType *) ptr1, (ArcType *) ptr2);
1636       break;
1637     case TEXT_TYPE:
1638       if (((LayerType *) ptr1)->On)
1639 	DrawText ((LayerType *) ptr1, (TextType *) ptr2);
1640       break;
1641     case POLYGON_TYPE:
1642       if (((LayerType *) ptr1)->On)
1643 	DrawPolygon ((LayerType *) ptr1, (PolygonType *) ptr2);
1644       break;
1645     case ELEMENT_TYPE:
1646       if (PCB->ElementOn &&
1647 	  (FRONT ((ElementType *) ptr2) || PCB->InvisibleObjectsOn))
1648 	DrawElement ((ElementType *) ptr2);
1649       break;
1650     case RATLINE_TYPE:
1651       if (PCB->RatOn)
1652 	DrawRat ((RatType *) ptr2);
1653       break;
1654     case PIN_TYPE:
1655       if (PCB->PinOn)
1656 	DrawPin ((PinType *) ptr2);
1657       break;
1658     case PAD_TYPE:
1659       if (PCB->PinOn)
1660 	DrawPad ((PadType *) ptr2);
1661       break;
1662     case ELEMENTNAME_TYPE:
1663       if (PCB->ElementOn &&
1664 	  (FRONT ((ElementType *) ptr2) || PCB->InvisibleObjectsOn))
1665 	DrawElementName ((ElementType *) ptr1);
1666       break;
1667     }
1668 }
1669 
1670 static void
draw_element(ElementType * element)1671 draw_element (ElementType *element)
1672 {
1673   draw_element_package (element);
1674   draw_element_name (element);
1675   draw_element_pins_and_pads (element);
1676 }
1677 
1678 /*!
1679  * \brief HID drawing callback.
1680  */
1681 void
hid_expose_callback(HID * hid,BoxType * region,void * item)1682 hid_expose_callback (HID * hid, BoxType * region, void *item)
1683 {
1684   HID *old_gui = gui;
1685 
1686   gui = hid;
1687   Output.fgGC = gui->graphics->make_gc ();
1688   Output.bgGC = gui->graphics->make_gc ();
1689   Output.pmGC = gui->graphics->make_gc ();
1690 
1691   hid->graphics->set_color (Output.pmGC, "erase");
1692   hid->graphics->set_color (Output.bgGC, "drill");
1693 
1694   if (item)
1695     {
1696       doing_pinout = true;
1697       draw_element ((ElementType *)item);
1698       doing_pinout = false;
1699     }
1700   else
1701     DrawEverything (region);
1702 
1703   gui->graphics->destroy_gc (Output.fgGC);
1704   gui->graphics->destroy_gc (Output.bgGC);
1705   gui->graphics->destroy_gc (Output.pmGC);
1706   gui = old_gui;
1707 }
1708