(no commit message)
[geda-pcb/pcjc2.git] / src / draw.c
bloba87adb452489b27cdd3558ddb05c754f24f0be97
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996, 2003, 2004 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
28 /* drawing routines
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
35 #include "global.h"
36 #include "hid_draw.h"
38 /*#include "clip.h"*/
39 #include "compat.h"
40 #include "crosshair.h"
41 #include "data.h"
42 #include "draw.h"
43 #include "error.h"
44 #include "mymem.h"
45 #include "misc.h"
46 #include "rotate.h"
47 #include "rtree.h"
48 #include "search.h"
49 #include "select.h"
50 #include "print.h"
52 #ifdef HAVE_LIBDMALLOC
53 #include <dmalloc.h>
54 #endif
56 #undef NDEBUG
57 #include <assert.h>
59 #ifndef MAXINT
60 #define MAXINT (((unsigned int)(~0))>>1)
61 #endif
63 #define SMALL_SMALL_TEXT_SIZE 0
64 #define SMALL_TEXT_SIZE 1
65 #define NORMAL_TEXT_SIZE 2
66 #define LARGE_TEXT_SIZE 3
67 #define N_TEXT_SIZES 4
70 /* ---------------------------------------------------------------------------
71 * some local identifiers
73 static BoxType Block = {MAXINT, MAXINT, -MAXINT, -MAXINT};
75 static int doing_pinout = 0;
76 static bool doing_assy = false;
78 /* ---------------------------------------------------------------------------
79 * some local prototypes
81 static void DrawEverything (const BoxType *);
82 static void DrawPPV (int group, const BoxType *);
83 static void AddPart (void *);
84 static void DrawEMark (ElementType *, Coord, Coord, bool);
85 static void DrawRats (const BoxType *);
87 static void
88 set_object_color (AnyObjectType *obj, char *warn_color, char *selected_color,
89 char *connected_color, char *found_color, char *normal_color)
91 char *color;
93 if (warn_color != NULL && TEST_FLAG (WARNFLAG, obj)) color = warn_color;
94 else if (selected_color != NULL && TEST_FLAG (SELECTEDFLAG, obj)) color = selected_color;
95 else if (connected_color != NULL && TEST_FLAG (CONNECTEDFLAG, obj)) color = connected_color;
96 else if (found_color != NULL && TEST_FLAG (FOUNDFLAG, obj)) color = found_color;
97 else color = normal_color;
99 gui->graphics->set_color (Output.fgGC, color);
102 static void
103 set_layer_object_color (LayerType *layer, AnyObjectType *obj)
105 set_object_color (obj, NULL, layer->SelectedColor, PCB->ConnectedColor, PCB->FoundColor, layer->Color);
108 /*---------------------------------------------------------------------------
109 * Adds the update rect to the update region
111 static void
112 AddPart (void *b)
114 BoxType *box = (BoxType *) b;
116 Block.X1 = MIN (Block.X1, box->X1);
117 Block.X2 = MAX (Block.X2, box->X2);
118 Block.Y1 = MIN (Block.Y1, box->Y1);
119 Block.Y2 = MAX (Block.Y2, box->Y2);
123 * initiate the actual redrawing of the updated area
125 void
126 Draw (void)
128 if (Block.X1 <= Block.X2 && Block.Y1 <= Block.Y2)
129 gui->invalidate_lr (Block.X1, Block.X2, Block.Y1, Block.Y2);
131 /* shrink the update block */
132 Block.X1 = Block.Y1 = MAXINT;
133 Block.X2 = Block.Y2 = -MAXINT;
136 /* ----------------------------------------------------------------------
137 * redraws all the data by the event handlers
139 void
140 Redraw (void)
142 gui->invalidate_all ();
145 static void
146 _draw_pv_name (PinType *pv)
148 BoxType box;
149 bool vert;
150 TextType text;
152 if (!pv->Name || !pv->Name[0])
153 text.TextString = EMPTY (pv->Number);
154 else
155 text.TextString = EMPTY (TEST_FLAG (SHOWNUMBERFLAG, PCB) ? pv->Number : pv->Name);
157 vert = TEST_FLAG (EDGE2FLAG, pv);
159 if (vert)
161 box.X1 = pv->X - pv->Thickness / 2 + Settings.PinoutTextOffsetY;
162 box.Y1 = pv->Y - pv->DrillingHole / 2 - Settings.PinoutTextOffsetX;
164 else
166 box.X1 = pv->X + pv->DrillingHole / 2 + Settings.PinoutTextOffsetX;
167 box.Y1 = pv->Y - pv->Thickness / 2 + Settings.PinoutTextOffsetY;
170 gui->graphics->set_color (Output.fgGC, PCB->PinNameColor);
172 text.Flags = NoFlags ();
173 /* Set font height to approx 56% of pin thickness */
174 text.Scale = 56 * pv->Thickness / FONT_CAPHEIGHT;
175 text.X = box.X1;
176 text.Y = box.Y1;
177 text.Direction = vert ? 1 : 0;
179 if (gui->gui)
180 doing_pinout++;
181 gui->graphics->draw_pcb_text (Output.fgGC, &text, 0);
182 if (gui->gui)
183 doing_pinout--;
186 static void
187 _draw_pv (PinType *pv, bool draw_hole)
189 if (TEST_FLAG (THINDRAWFLAG, PCB))
190 gui->graphics->thindraw_pcb_pv (Output.fgGC, Output.fgGC, pv, draw_hole, false);
191 else
192 gui->graphics->fill_pcb_pv (Output.fgGC, Output.bgGC, pv, draw_hole, false);
194 if ((!TEST_FLAG (HOLEFLAG, pv) && TEST_FLAG (DISPLAYNAMEFLAG, pv)) || doing_pinout)
195 _draw_pv_name (pv);
198 static void
199 draw_pin (PinType *pin, bool draw_hole)
201 if (doing_pinout)
202 gui->graphics->set_color (Output.fgGC, PCB->PinColor);
203 else
204 set_object_color ((AnyObjectType *)pin,
205 PCB->WarnColor, PCB->PinSelectedColor,
206 PCB->ConnectedColor, PCB->FoundColor, PCB->PinColor);
208 _draw_pv (pin, draw_hole);
211 static int
212 pin_callback (const BoxType * b, void *cl)
214 draw_pin ((PinType *)b, false);
215 return 1;
218 static void
219 draw_via (PinType *via, bool draw_hole)
221 if (doing_pinout)
222 gui->graphics->set_color (Output.fgGC, PCB->ViaColor);
223 else
224 set_object_color ((AnyObjectType *)via,
225 PCB->WarnColor, PCB->ViaSelectedColor,
226 PCB->ConnectedColor, PCB->FoundColor, PCB->ViaColor);
228 _draw_pv (via, draw_hole);
231 static int
232 via_callback (const BoxType * b, void *cl)
234 draw_via ((PinType *)b, false);
235 return 1;
238 static void
239 draw_pad_name (PadType *pad)
241 BoxType box;
242 bool vert;
243 TextType text;
245 if (!pad->Name || !pad->Name[0])
246 text.TextString = EMPTY (pad->Number);
247 else
248 text.TextString = EMPTY (TEST_FLAG (SHOWNUMBERFLAG, PCB) ? pad->Number : pad->Name);
250 /* should text be vertical ? */
251 vert = (pad->Point1.X == pad->Point2.X);
253 if (vert)
255 box.X1 = pad->Point1.X - pad->Thickness / 2;
256 box.Y1 = MAX (pad->Point1.Y, pad->Point2.Y) + pad->Thickness / 2;
257 box.X1 += Settings.PinoutTextOffsetY;
258 box.Y1 -= Settings.PinoutTextOffsetX;
260 else
262 box.X1 = MIN (pad->Point1.X, pad->Point2.X) - pad->Thickness / 2;
263 box.Y1 = pad->Point1.Y - pad->Thickness / 2;
264 box.X1 += Settings.PinoutTextOffsetX;
265 box.Y1 += Settings.PinoutTextOffsetY;
268 gui->graphics->set_color (Output.fgGC, PCB->PinNameColor);
270 text.Flags = NoFlags ();
271 /* Set font height to approx 90% of pin thickness */
272 text.Scale = 90 * pad->Thickness / FONT_CAPHEIGHT;
273 text.X = box.X1;
274 text.Y = box.Y1;
275 text.Direction = vert ? 1 : 0;
277 gui->graphics->draw_pcb_text (Output.fgGC, &text, 0);
280 static void
281 _draw_pad (hidGC gc, PadType *pad, bool clear, bool mask)
283 if (clear && !mask && pad->Clearance <= 0)
284 return;
286 if (TEST_FLAG (THINDRAWFLAG, PCB) ||
287 (clear && TEST_FLAG (THINDRAWPOLYFLAG, PCB)))
288 gui->graphics->thindraw_pcb_pad (gc, pad, clear, mask);
289 else
290 gui->graphics->fill_pcb_pad (gc, pad, clear, mask);
293 static void
294 draw_pad (PadType *pad)
296 if (doing_pinout)
297 gui->graphics->set_color (Output.fgGC, PCB->PinColor);
298 else
299 set_object_color ((AnyObjectType *)pad, PCB->WarnColor,
300 PCB->PinSelectedColor, PCB->ConnectedColor, PCB->FoundColor,
301 FRONT (pad) ? PCB->PinColor : PCB->InvisibleObjectsColor);
303 _draw_pad (Output.fgGC, pad, false, false);
305 if (doing_pinout || TEST_FLAG (DISPLAYNAMEFLAG, pad))
306 draw_pad_name (pad);
309 static int
310 pad_callback (const BoxType * b, void *cl)
312 PadType *pad = (PadType *) b;
313 int *side = cl;
315 if (ON_SIDE (pad, *side))
316 draw_pad (pad);
317 return 1;
320 static void
321 draw_element_name (ElementType *element)
323 if ((TEST_FLAG (HIDENAMESFLAG, PCB) && gui->gui) ||
324 TEST_FLAG (HIDENAMEFLAG, element))
325 return;
326 if (doing_pinout || doing_assy)
327 gui->graphics->set_color (Output.fgGC, PCB->ElementColor);
328 else if (TEST_FLAG (SELECTEDFLAG, &ELEMENT_TEXT (PCB, element)))
329 gui->graphics->set_color (Output.fgGC, PCB->ElementSelectedColor);
330 else if (FRONT (element))
331 gui->graphics->set_color (Output.fgGC, PCB->ElementColor);
332 else
333 gui->graphics->set_color (Output.fgGC, PCB->InvisibleObjectsColor);
334 gui->graphics->draw_pcb_text (Output.fgGC, &ELEMENT_TEXT (PCB, element), PCB->minSlk);
337 static int
338 name_callback (const BoxType * b, void *cl)
340 TextType *text = (TextType *) b;
341 ElementType *element = (ElementType *) text->Element;
342 int *side = cl;
344 if (TEST_FLAG (HIDENAMEFLAG, element))
345 return 0;
347 if (ON_SIDE (element, *side))
348 draw_element_name (element);
349 return 0;
352 static void
353 draw_element_pins_and_pads (ElementType *element)
355 PAD_LOOP (element);
357 if (doing_pinout || doing_assy || FRONT (pad) || PCB->InvisibleObjectsOn)
358 draw_pad (pad);
360 END_LOOP;
361 PIN_LOOP (element);
363 draw_pin (pin, true);
365 END_LOOP;
368 static int
369 EMark_callback (const BoxType * b, void *cl)
371 ElementType *element = (ElementType *) b;
373 DrawEMark (element, element->MarkX, element->MarkY, !FRONT (element));
374 return 1;
377 static int
378 hole_callback (const BoxType * b, void *cl)
380 PinType *pv = (PinType *) b;
381 int plated = cl ? *(int *) cl : -1;
383 if ((plated == 0 && !TEST_FLAG (HOLEFLAG, pv)) ||
384 (plated == 1 && TEST_FLAG (HOLEFLAG, pv)))
385 return 1;
387 if (TEST_FLAG (THINDRAWFLAG, PCB))
389 if (!TEST_FLAG (HOLEFLAG, pv))
391 gui->graphics->set_line_cap (Output.fgGC, Round_Cap);
392 gui->graphics->set_line_width (Output.fgGC, 0);
393 gui->graphics->draw_arc (Output.fgGC,
394 pv->X, pv->Y, pv->DrillingHole / 2,
395 pv->DrillingHole / 2, 0, 360);
398 else
399 gui->graphics->fill_circle (Output.bgGC, pv->X, pv->Y, pv->DrillingHole / 2);
401 if (TEST_FLAG (HOLEFLAG, pv))
403 set_object_color ((AnyObjectType *) pv,
404 PCB->WarnColor, PCB->ViaSelectedColor,
405 NULL, NULL, Settings.BlackColor);
407 gui->graphics->set_line_cap (Output.fgGC, Round_Cap);
408 gui->graphics->set_line_width (Output.fgGC, 0);
409 gui->graphics->draw_arc (Output.fgGC,
410 pv->X, pv->Y, pv->DrillingHole / 2,
411 pv->DrillingHole / 2, 0, 360);
413 return 1;
416 void
417 DrawHoles (bool draw_plated, bool draw_unplated, const BoxType *drawn_area)
419 int plated = -1;
421 if ( draw_plated && !draw_unplated) plated = 1;
422 if (!draw_plated && draw_unplated) plated = 0;
424 r_search (PCB->Data->pin_tree, drawn_area, NULL, hole_callback, &plated);
425 r_search (PCB->Data->via_tree, drawn_area, NULL, hole_callback, &plated);
428 static int
429 line_callback (const BoxType * b, void *cl)
431 LayerType *layer = (LayerType *) cl;
432 LineType *line = (LineType *) b;
434 set_layer_object_color (layer, (AnyObjectType *) line);
435 gui->graphics->draw_pcb_line (Output.fgGC, line);
437 return 1;
440 static int
441 rat_callback (const BoxType * b, void *cl)
443 RatType *rat = (RatType *)b;
445 set_object_color ((AnyObjectType *) rat, NULL, PCB->RatSelectedColor,
446 PCB->ConnectedColor, PCB->FoundColor, PCB->RatColor);
448 if (Settings.RatThickness < 100)
449 rat->Thickness = pixel_slop * Settings.RatThickness;
450 /* rats.c set VIAFLAG if this rat goes to a containing poly: draw a donut */
451 if (TEST_FLAG(VIAFLAG, rat))
453 int w = rat->Thickness;
455 if (TEST_FLAG (THINDRAWFLAG, PCB))
456 gui->graphics->set_line_width (Output.fgGC, 0);
457 else
458 gui->graphics->set_line_width (Output.fgGC, w);
459 gui->graphics->draw_arc (Output.fgGC, rat->Point1.X, rat->Point1.Y,
460 w * 2, w * 2, 0, 360);
462 else
463 gui->graphics->draw_pcb_line (Output.fgGC, (LineType *) rat);
464 return 1;
467 static int
468 arc_callback (const BoxType * b, void *cl)
470 LayerType *layer = (LayerType *) cl;
471 ArcType *arc = (ArcType *) b;
473 set_layer_object_color (layer, (AnyObjectType *) arc);
474 gui->graphics->draw_pcb_arc (Output.fgGC, arc);
476 return 1;
479 static void
480 draw_element_package (ElementType *element)
482 /* set color and draw lines, arcs, text and pins */
483 if (doing_pinout || doing_assy)
484 gui->graphics->set_color (Output.fgGC, PCB->ElementColor);
485 else if (TEST_FLAG (SELECTEDFLAG, element))
486 gui->graphics->set_color (Output.fgGC, PCB->ElementSelectedColor);
487 else if (FRONT (element))
488 gui->graphics->set_color (Output.fgGC, PCB->ElementColor);
489 else
490 gui->graphics->set_color (Output.fgGC, PCB->InvisibleObjectsColor);
492 /* draw lines, arcs, text and pins */
493 ELEMENTLINE_LOOP (element);
495 gui->graphics->draw_pcb_line (Output.fgGC, line);
497 END_LOOP;
498 ARC_LOOP (element);
500 gui->graphics->draw_pcb_arc (Output.fgGC, arc);
502 END_LOOP;
505 static int
506 element_callback (const BoxType * b, void *cl)
508 ElementType *element = (ElementType *) b;
509 int *side = cl;
511 if (ON_SIDE (element, *side))
512 draw_element_package (element);
513 return 1;
516 /* ---------------------------------------------------------------------------
517 * prints assembly drawing.
520 void
521 PrintAssembly (int side, const BoxType * drawn_area)
523 int side_group = GetLayerGroupNumberBySide (side);
525 doing_assy = true;
526 gui->graphics->set_draw_faded (Output.fgGC, 1);
527 DrawLayerGroup (side_group, drawn_area);
528 gui->graphics->set_draw_faded (Output.fgGC, 0);
530 /* draw package */
531 DrawSilk (side, drawn_area);
532 doing_assy = false;
535 /* ---------------------------------------------------------------------------
536 * initializes some identifiers for a new zoom factor and redraws whole screen
538 static void
539 DrawEverything (const BoxType *drawn_area)
541 int i, ngroups, side;
542 int top_group, bottom_group;
543 /* This is the list of layer groups we will draw. */
544 int do_group[MAX_GROUP];
545 /* This is the reverse of the order in which we draw them. */
546 int drawn_groups[MAX_GROUP];
547 int plated, unplated;
548 bool paste_empty;
550 PCB->Data->SILKLAYER.Color = PCB->ElementColor;
551 PCB->Data->BACKSILKLAYER.Color = PCB->InvisibleObjectsColor;
553 memset (do_group, 0, sizeof (do_group));
554 for (ngroups = 0, i = 0; i < max_copper_layer; i++)
556 LayerType *l = LAYER_ON_STACK (i);
557 int group = GetLayerGroupNumberByNumber (LayerStack[i]);
558 if (l->On && !do_group[group])
560 do_group[group] = 1;
561 drawn_groups[ngroups++] = group;
565 top_group = GetLayerGroupNumberBySide (TOP_SIDE);
566 bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
569 * first draw all 'invisible' stuff
571 if (!TEST_FLAG (CHECKPLANESFLAG, PCB)
572 && gui->set_layer ("invisible", SL (INVISIBLE, 0), 0))
574 side = SWAP_IDENT ? TOP_SIDE : BOTTOM_SIDE;
575 if (PCB->ElementOn)
577 r_search (PCB->Data->element_tree, drawn_area, NULL, element_callback, &side);
578 r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], drawn_area, NULL, name_callback, &side);
579 DrawLayer (&(PCB->Data->Layer[max_copper_layer + side]), drawn_area);
581 r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side);
582 gui->end_layer ();
585 /* draw all layers in layerstack order */
586 for (i = ngroups - 1; i >= 0; i--)
588 int group = drawn_groups[i];
590 if (gui->set_layer (0, group, 0))
592 DrawLayerGroup (group, drawn_area);
593 gui->end_layer ();
597 if (TEST_FLAG (CHECKPLANESFLAG, PCB) && gui->gui)
598 return;
600 /* Draw pins, pads, vias below silk */
601 if (gui->gui)
602 DrawPPV (SWAP_IDENT ? bottom_group : top_group, drawn_area);
603 else
605 CountHoles (&plated, &unplated, drawn_area);
607 if (plated && gui->set_layer ("plated-drill", SL (PDRILL, 0), 0))
609 DrawHoles (true, false, drawn_area);
610 gui->end_layer ();
613 if (unplated && gui->set_layer ("unplated-drill", SL (UDRILL, 0), 0))
615 DrawHoles (false, true, drawn_area);
616 gui->end_layer ();
620 /* Draw the solder mask if turned on */
621 if (gui->set_layer ("componentmask", SL (MASK, TOP), 0))
623 DrawMask (TOP_SIDE, drawn_area);
624 gui->end_layer ();
627 if (gui->set_layer ("soldermask", SL (MASK, BOTTOM), 0))
629 DrawMask (BOTTOM_SIDE, drawn_area);
630 gui->end_layer ();
633 if (gui->set_layer ("topsilk", SL (SILK, TOP), 0))
635 DrawSilk (TOP_SIDE, drawn_area);
636 gui->end_layer ();
639 if (gui->set_layer ("bottomsilk", SL (SILK, BOTTOM), 0))
641 DrawSilk (BOTTOM_SIDE, drawn_area);
642 gui->end_layer ();
645 if (gui->gui)
647 /* Draw element Marks */
648 if (PCB->PinOn)
649 r_search (PCB->Data->element_tree, drawn_area, NULL, EMark_callback,
650 NULL);
651 /* Draw rat lines on top */
652 if (gui->set_layer ("rats", SL (RATS, 0), 0))
654 DrawRats(drawn_area);
655 gui->end_layer ();
659 paste_empty = IsPasteEmpty (TOP_SIDE);
660 if (gui->set_layer ("toppaste", SL (PASTE, TOP), paste_empty))
662 DrawPaste (TOP_SIDE, drawn_area);
663 gui->end_layer ();
666 paste_empty = IsPasteEmpty (BOTTOM_SIDE);
667 if (gui->set_layer ("bottompaste", SL (PASTE, BOTTOM), paste_empty))
669 DrawPaste (BOTTOM_SIDE, drawn_area);
670 gui->end_layer ();
673 if (gui->set_layer ("topassembly", SL (ASSY, TOP), 0))
675 PrintAssembly (TOP_SIDE, drawn_area);
676 gui->end_layer ();
679 if (gui->set_layer ("bottomassembly", SL (ASSY, BOTTOM), 0))
681 PrintAssembly (BOTTOM_SIDE, drawn_area);
682 gui->end_layer ();
685 if (gui->set_layer ("fab", SL (FAB, 0), 0))
687 PrintFab (Output.fgGC);
688 gui->end_layer ();
692 static void
693 DrawEMark (ElementType *e, Coord X, Coord Y, bool invisible)
695 Coord mark_size = EMARK_SIZE;
696 if (!PCB->InvisibleObjectsOn && invisible)
697 return;
699 if (e->Pin != NULL)
701 PinType *pin0 = e->Pin->data;
702 if (TEST_FLAG (HOLEFLAG, pin0))
703 mark_size = MIN (mark_size, pin0->DrillingHole / 2);
704 else
705 mark_size = MIN (mark_size, pin0->Thickness / 2);
708 if (e->Pad != NULL)
710 PadType *pad0 = e->Pad->data;
711 mark_size = MIN (mark_size, pad0->Thickness / 2);
714 gui->graphics->set_color (Output.fgGC,
715 invisible ? PCB->InvisibleMarkColor : PCB->ElementColor);
716 gui->graphics->set_line_cap (Output.fgGC, Trace_Cap);
717 gui->graphics->set_line_width (Output.fgGC, 0);
718 gui->graphics->draw_line (Output.fgGC, X - mark_size, Y, X, Y - mark_size);
719 gui->graphics->draw_line (Output.fgGC, X + mark_size, Y, X, Y - mark_size);
720 gui->graphics->draw_line (Output.fgGC, X - mark_size, Y, X, Y + mark_size);
721 gui->graphics->draw_line (Output.fgGC, X + mark_size, Y, X, Y + mark_size);
724 * If an element is locked, place a "L" on top of the "diamond".
725 * This provides a nice visual indication that it is locked that
726 * works even for color blind users.
728 if (TEST_FLAG (LOCKFLAG, e) )
730 gui->graphics->draw_line (Output.fgGC, X, Y, X + 2 * mark_size, Y);
731 gui->graphics->draw_line (Output.fgGC, X, Y, X, Y - 4* mark_size);
735 /* ---------------------------------------------------------------------------
736 * Draws pins pads and vias - Always draws for non-gui HIDs,
737 * otherwise drawing depends on PCB->PinOn and PCB->ViaOn
739 static void
740 DrawPPV (int group, const BoxType *drawn_area)
742 int top_group = GetLayerGroupNumberBySide (TOP_SIDE);
743 int bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
744 int side;
746 if (PCB->PinOn || !gui->gui)
748 /* draw element pins */
749 r_search (PCB->Data->pin_tree, drawn_area, NULL, pin_callback, NULL);
751 /* draw element pads */
752 if (group == top_group)
754 side = TOP_SIDE;
755 r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side);
758 if (group == bottom_group)
760 side = BOTTOM_SIDE;
761 r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side);
765 /* draw vias */
766 if (PCB->ViaOn || !gui->gui)
768 r_search (PCB->Data->via_tree, drawn_area, NULL, via_callback, NULL);
769 r_search (PCB->Data->via_tree, drawn_area, NULL, hole_callback, NULL);
771 if (PCB->PinOn || doing_assy)
772 r_search (PCB->Data->pin_tree, drawn_area, NULL, hole_callback, NULL);
775 static int
776 clearPin_callback (const BoxType * b, void *cl)
778 PinType *pin = (PinType *) b;
779 if (TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG (THINDRAWPOLYFLAG, PCB))
780 gui->graphics->thindraw_pcb_pv (Output.pmGC, Output.pmGC, pin, false, true);
781 else
782 gui->graphics->fill_pcb_pv (Output.pmGC, Output.pmGC, pin, false, true);
783 return 1;
786 struct poly_info {
787 const BoxType *drawn_area;
788 LayerType *layer;
791 static int
792 poly_callback (const BoxType * b, void *cl)
794 struct poly_info *i = cl;
795 PolygonType *polygon = (PolygonType *)b;
797 set_layer_object_color (i->layer, (AnyObjectType *) polygon);
799 gui->graphics->draw_pcb_polygon (Output.fgGC, polygon, i->drawn_area);
801 return 1;
804 static int
805 clearPad_callback (const BoxType * b, void *cl)
807 PadType *pad = (PadType *) b;
808 int *side = cl;
809 if (ON_SIDE (pad, *side) && pad->Mask)
810 _draw_pad (Output.pmGC, pad, true, true);
811 return 1;
814 /* ---------------------------------------------------------------------------
815 * Draws silk layer.
818 void
819 DrawSilk (int side, const BoxType * drawn_area)
821 #if 0
822 /* This code is used when you want to mask silk to avoid exposed
823 pins and pads. We decided it was a bad idea to do this
824 unconditionally, but the code remains. */
825 #endif
827 #if 0
828 if (gui->poly_before)
830 gui->graphics->use_mask (HID_MASK_BEFORE);
831 #endif
832 DrawLayer (LAYER_PTR (max_copper_layer + side), drawn_area);
833 /* draw package */
834 r_search (PCB->Data->element_tree, drawn_area, NULL, element_callback, &side);
835 r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], drawn_area, NULL, name_callback, &side);
836 #if 0
839 gui->graphics->use_mask (HID_MASK_CLEAR);
840 r_search (PCB->Data->pin_tree, drawn_area, NULL, clearPin_callback, NULL);
841 r_search (PCB->Data->via_tree, drawn_area, NULL, clearPin_callback, NULL);
842 r_search (PCB->Data->pad_tree, drawn_area, NULL, clearPad_callback, &side);
844 if (gui->poly_after)
846 gui->graphics->use_mask (HID_MASK_AFTER);
847 DrawLayer (LAYER_PTR (max_copper_layer + layer), drawn_area);
848 /* draw package */
849 r_search (PCB->Data->element_tree, drawn_area, NULL, element_callback, &side);
850 r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], drawn_area, NULL, name_callback, &side);
852 gui->graphics->use_mask (HID_MASK_OFF);
853 #endif
857 static void
858 DrawMaskBoardArea (int mask_type, const BoxType *drawn_area)
860 /* Skip the mask drawing if the GUI doesn't want this type */
861 if ((mask_type == HID_MASK_BEFORE && !gui->poly_before) ||
862 (mask_type == HID_MASK_AFTER && !gui->poly_after))
863 return;
865 gui->graphics->use_mask (mask_type);
866 gui->graphics->set_color (Output.fgGC, PCB->MaskColor);
867 if (drawn_area == NULL)
868 gui->graphics->fill_rect (Output.fgGC, 0, 0, PCB->MaxWidth, PCB->MaxHeight);
869 else
870 gui->graphics->fill_rect (Output.fgGC, drawn_area->X1, drawn_area->Y1,
871 drawn_area->X2, drawn_area->Y2);
874 /* ---------------------------------------------------------------------------
875 * draws solder mask layer - this will cover nearly everything
877 void
878 DrawMask (int side, const BoxType *screen)
880 int thin = TEST_FLAG(THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB);
882 if (thin)
883 gui->graphics->set_color (Output.pmGC, PCB->MaskColor);
884 else
886 DrawMaskBoardArea (HID_MASK_BEFORE, screen);
887 gui->graphics->use_mask (HID_MASK_CLEAR);
890 r_search (PCB->Data->pin_tree, screen, NULL, clearPin_callback, NULL);
891 r_search (PCB->Data->via_tree, screen, NULL, clearPin_callback, NULL);
892 r_search (PCB->Data->pad_tree, screen, NULL, clearPad_callback, &side);
894 if (thin)
895 gui->graphics->set_color (Output.pmGC, "erase");
896 else
898 DrawMaskBoardArea (HID_MASK_AFTER, screen);
899 gui->graphics->use_mask (HID_MASK_OFF);
903 /* ---------------------------------------------------------------------------
904 * draws solder paste layer for a given side of the board
906 void
907 DrawPaste (int side, const BoxType *drawn_area)
909 gui->graphics->set_color (Output.fgGC, PCB->ElementColor);
910 ALLPAD_LOOP (PCB->Data);
912 if (ON_SIDE (pad, side) && !TEST_FLAG (NOPASTEFLAG, pad) && pad->Mask > 0)
914 if (pad->Mask < pad->Thickness)
915 _draw_pad (Output.fgGC, pad, true, true);
916 else
917 _draw_pad (Output.fgGC, pad, false, false);
920 ENDALL_LOOP;
923 static void
924 DrawRats (const BoxType *drawn_area)
927 * XXX lesstif allows positive AND negative drawing in HID_MASK_CLEAR.
928 * XXX gtk only allows negative drawing.
929 * XXX using the mask here is to get rat transparency
931 int can_mask = strcmp(gui->name, "lesstif") == 0;
933 if (can_mask)
934 gui->graphics->use_mask (HID_MASK_CLEAR);
935 r_search (PCB->Data->rat_tree, drawn_area, NULL, rat_callback, NULL);
936 if (can_mask)
937 gui->graphics->use_mask (HID_MASK_OFF);
940 static int
941 text_callback (const BoxType * b, void *cl)
943 LayerType *layer = cl;
944 TextType *text = (TextType *)b;
945 int min_silk_line;
947 if (TEST_FLAG (SELECTEDFLAG, text))
948 gui->graphics->set_color (Output.fgGC, layer->SelectedColor);
949 else
950 gui->graphics->set_color (Output.fgGC, layer->Color);
951 if (layer == &PCB->Data->SILKLAYER ||
952 layer == &PCB->Data->BACKSILKLAYER)
953 min_silk_line = PCB->minSlk;
954 else
955 min_silk_line = PCB->minWid;
956 gui->graphics->draw_pcb_text (Output.fgGC, text, min_silk_line);
957 return 1;
960 void
961 DrawLayer (LayerType *Layer, const BoxType *screen)
963 struct poly_info info = {screen, Layer};
965 /* print the non-clearing polys */
966 r_search (Layer->polygon_tree, screen, NULL, poly_callback, &info);
968 if (TEST_FLAG (CHECKPLANESFLAG, PCB))
969 return;
971 /* draw all visible lines this layer */
972 r_search (Layer->line_tree, screen, NULL, line_callback, Layer);
974 /* draw the layer arcs on screen */
975 r_search (Layer->arc_tree, screen, NULL, arc_callback, Layer);
977 /* draw the layer text on screen */
978 r_search (Layer->text_tree, screen, NULL, text_callback, Layer);
980 /* We should check for gui->gui here, but it's kinda cool seeing the
981 auto-outline magically disappear when you first add something to
982 the "outline" layer. */
983 if (IsLayerEmpty (Layer)
984 && (strcmp (Layer->Name, "outline") == 0
985 || strcmp (Layer->Name, "route") == 0))
987 gui->graphics->set_color (Output.fgGC, Layer->Color);
988 gui->graphics->set_line_width (Output.fgGC, PCB->minWid);
989 gui->graphics->draw_rect (Output.fgGC,
990 0, 0,
991 PCB->MaxWidth, PCB->MaxHeight);
995 /* ---------------------------------------------------------------------------
996 * draws one layer group. If the exporter is not a GUI,
997 * also draws the pins / pads / vias in this layer group.
999 void
1000 DrawLayerGroup (int group, const BoxType *drawn_area)
1002 int i, rv = 1;
1003 int layernum;
1004 LayerType *Layer;
1005 int n_entries = PCB->LayerGroups.Number[group];
1006 Cardinal *layers = PCB->LayerGroups.Entries[group];
1008 for (i = n_entries - 1; i >= 0; i--)
1010 layernum = layers[i];
1011 Layer = PCB->Data->Layer + layers[i];
1012 if (strcmp (Layer->Name, "outline") == 0 ||
1013 strcmp (Layer->Name, "route") == 0)
1014 rv = 0;
1015 if (layernum < max_copper_layer && Layer->On)
1016 DrawLayer (Layer, drawn_area);
1018 if (n_entries > 1)
1019 rv = 1;
1021 if (rv && !gui->gui)
1022 DrawPPV (group, drawn_area);
1025 static void
1026 GatherPVName (PinType *Ptr)
1028 BoxType box;
1029 bool vert = TEST_FLAG (EDGE2FLAG, Ptr);
1031 if (vert)
1033 box.X1 = Ptr->X - Ptr->Thickness / 2 + Settings.PinoutTextOffsetY;
1034 box.Y1 = Ptr->Y - Ptr->DrillingHole / 2 - Settings.PinoutTextOffsetX;
1036 else
1038 box.X1 = Ptr->X + Ptr->DrillingHole / 2 + Settings.PinoutTextOffsetX;
1039 box.Y1 = Ptr->Y - Ptr->Thickness / 2 + Settings.PinoutTextOffsetY;
1042 if (vert)
1044 box.X2 = box.X1;
1045 box.Y2 = box.Y1;
1047 else
1049 box.X2 = box.X1;
1050 box.Y2 = box.Y1;
1052 AddPart (&box);
1055 static void
1056 GatherPadName (PadType *Pad)
1058 BoxType box;
1059 bool vert;
1061 /* should text be vertical ? */
1062 vert = (Pad->Point1.X == Pad->Point2.X);
1064 if (vert)
1066 box.X1 = Pad->Point1.X - Pad->Thickness / 2;
1067 box.Y1 = MAX (Pad->Point1.Y, Pad->Point2.Y) + Pad->Thickness / 2;
1068 box.X1 += Settings.PinoutTextOffsetY;
1069 box.Y1 -= Settings.PinoutTextOffsetX;
1070 box.X2 = box.X1;
1071 box.Y2 = box.Y1;
1073 else
1075 box.X1 = MIN (Pad->Point1.X, Pad->Point2.X) - Pad->Thickness / 2;
1076 box.Y1 = Pad->Point1.Y - Pad->Thickness / 2;
1077 box.X1 += Settings.PinoutTextOffsetX;
1078 box.Y1 += Settings.PinoutTextOffsetY;
1079 box.X2 = box.X1;
1080 box.Y2 = box.Y1;
1083 AddPart (&box);
1084 return;
1087 /* ---------------------------------------------------------------------------
1088 * draw a via object
1090 void
1091 DrawVia (PinType *Via)
1093 AddPart (Via);
1094 if (!TEST_FLAG (HOLEFLAG, Via) && TEST_FLAG (DISPLAYNAMEFLAG, Via))
1095 DrawViaName (Via);
1098 /* ---------------------------------------------------------------------------
1099 * draws the name of a via
1101 void
1102 DrawViaName (PinType *Via)
1104 GatherPVName (Via);
1107 /* ---------------------------------------------------------------------------
1108 * draw a pin object
1110 void
1111 DrawPin (PinType *Pin)
1113 AddPart (Pin);
1114 if ((!TEST_FLAG (HOLEFLAG, Pin) && TEST_FLAG (DISPLAYNAMEFLAG, Pin))
1115 || doing_pinout)
1116 DrawPinName (Pin);
1119 /* ---------------------------------------------------------------------------
1120 * draws the name of a pin
1122 void
1123 DrawPinName (PinType *Pin)
1125 GatherPVName (Pin);
1128 /* ---------------------------------------------------------------------------
1129 * draw a pad object
1131 void
1132 DrawPad (PadType *Pad)
1134 AddPart (Pad);
1135 if (doing_pinout || TEST_FLAG (DISPLAYNAMEFLAG, Pad))
1136 DrawPadName (Pad);
1139 /* ---------------------------------------------------------------------------
1140 * draws the name of a pad
1142 void
1143 DrawPadName (PadType *Pad)
1145 GatherPadName (Pad);
1148 /* ---------------------------------------------------------------------------
1149 * draws a line on a layer
1151 void
1152 DrawLine (LayerType *Layer, LineType *Line)
1154 AddPart (Line);
1157 /* ---------------------------------------------------------------------------
1158 * draws a ratline
1160 void
1161 DrawRat (RatType *Rat)
1163 if (Settings.RatThickness < 100)
1164 Rat->Thickness = pixel_slop * Settings.RatThickness;
1165 /* rats.c set VIAFLAG if this rat goes to a containing poly: draw a donut */
1166 if (TEST_FLAG(VIAFLAG, Rat))
1168 Coord w = Rat->Thickness;
1170 BoxType b;
1172 b.X1 = Rat->Point1.X - w * 2 - w / 2;
1173 b.X2 = Rat->Point1.X + w * 2 + w / 2;
1174 b.Y1 = Rat->Point1.Y - w * 2 - w / 2;
1175 b.Y2 = Rat->Point1.Y + w * 2 + w / 2;
1176 AddPart (&b);
1178 else
1179 DrawLine (NULL, (LineType *)Rat);
1182 /* ---------------------------------------------------------------------------
1183 * draws an arc on a layer
1185 void
1186 DrawArc (LayerType *Layer, ArcType *Arc)
1188 AddPart (Arc);
1191 /* ---------------------------------------------------------------------------
1192 * draws a text on a layer
1194 void
1195 DrawText (LayerType *Layer, TextType *Text)
1197 AddPart (Text);
1201 /* ---------------------------------------------------------------------------
1202 * draws a polygon on a layer
1204 void
1205 DrawPolygon (LayerType *Layer, PolygonType *Polygon)
1207 AddPart (Polygon);
1210 /* ---------------------------------------------------------------------------
1211 * draws an element
1213 void
1214 DrawElement (ElementType *Element)
1216 DrawElementPackage (Element);
1217 DrawElementName (Element);
1218 DrawElementPinsAndPads (Element);
1221 /* ---------------------------------------------------------------------------
1222 * draws the name of an element
1224 void
1225 DrawElementName (ElementType *Element)
1227 if (TEST_FLAG (HIDENAMEFLAG, Element))
1228 return;
1229 DrawText (NULL, &ELEMENT_TEXT (PCB, Element));
1232 /* ---------------------------------------------------------------------------
1233 * draws the package of an element
1235 void
1236 DrawElementPackage (ElementType *Element)
1238 ELEMENTLINE_LOOP (Element);
1240 DrawLine (NULL, line);
1242 END_LOOP;
1243 ARC_LOOP (Element);
1245 DrawArc (NULL, arc);
1247 END_LOOP;
1250 /* ---------------------------------------------------------------------------
1251 * draw pins of an element
1253 void
1254 DrawElementPinsAndPads (ElementType *Element)
1256 PAD_LOOP (Element);
1258 if (doing_pinout || doing_assy || FRONT (pad) || PCB->InvisibleObjectsOn)
1259 DrawPad (pad);
1261 END_LOOP;
1262 PIN_LOOP (Element);
1264 DrawPin (pin);
1266 END_LOOP;
1269 /* ---------------------------------------------------------------------------
1270 * erase a via
1272 void
1273 EraseVia (PinType *Via)
1275 AddPart (Via);
1276 if (TEST_FLAG (DISPLAYNAMEFLAG, Via))
1277 EraseViaName (Via);
1280 /* ---------------------------------------------------------------------------
1281 * erase a ratline
1283 void
1284 EraseRat (RatType *Rat)
1286 if (TEST_FLAG(VIAFLAG, Rat))
1288 Coord w = Rat->Thickness;
1290 BoxType b;
1292 b.X1 = Rat->Point1.X - w * 2 - w / 2;
1293 b.X2 = Rat->Point1.X + w * 2 + w / 2;
1294 b.Y1 = Rat->Point1.Y - w * 2 - w / 2;
1295 b.Y2 = Rat->Point1.Y + w * 2 + w / 2;
1296 AddPart (&b);
1298 else
1299 EraseLine ((LineType *)Rat);
1303 /* ---------------------------------------------------------------------------
1304 * erase a via name
1306 void
1307 EraseViaName (PinType *Via)
1309 GatherPVName (Via);
1312 /* ---------------------------------------------------------------------------
1313 * erase a pad object
1315 void
1316 ErasePad (PadType *Pad)
1318 AddPart (Pad);
1319 if (TEST_FLAG (DISPLAYNAMEFLAG, Pad))
1320 ErasePadName (Pad);
1323 /* ---------------------------------------------------------------------------
1324 * erase a pad name
1326 void
1327 ErasePadName (PadType *Pad)
1329 GatherPadName (Pad);
1332 /* ---------------------------------------------------------------------------
1333 * erase a pin object
1335 void
1336 ErasePin (PinType *Pin)
1338 AddPart (Pin);
1339 if (TEST_FLAG (DISPLAYNAMEFLAG, Pin))
1340 ErasePinName (Pin);
1343 /* ---------------------------------------------------------------------------
1344 * erase a pin name
1346 void
1347 ErasePinName (PinType *Pin)
1349 GatherPVName (Pin);
1352 /* ---------------------------------------------------------------------------
1353 * erases a line on a layer
1355 void
1356 EraseLine (LineType *Line)
1358 AddPart (Line);
1361 /* ---------------------------------------------------------------------------
1362 * erases an arc on a layer
1364 void
1365 EraseArc (ArcType *Arc)
1367 if (!Arc->Thickness)
1368 return;
1369 AddPart (Arc);
1372 /* ---------------------------------------------------------------------------
1373 * erases a text on a layer
1375 void
1376 EraseText (LayerType *Layer, TextType *Text)
1378 AddPart (Text);
1381 /* ---------------------------------------------------------------------------
1382 * erases a polygon on a layer
1384 void
1385 ErasePolygon (PolygonType *Polygon)
1387 AddPart (Polygon);
1390 /* ---------------------------------------------------------------------------
1391 * erases an element
1393 void
1394 EraseElement (ElementType *Element)
1396 ELEMENTLINE_LOOP (Element);
1398 EraseLine (line);
1400 END_LOOP;
1401 ARC_LOOP (Element);
1403 EraseArc (arc);
1405 END_LOOP;
1406 EraseElementName (Element);
1407 EraseElementPinsAndPads (Element);
1410 /* ---------------------------------------------------------------------------
1411 * erases all pins and pads of an element
1413 void
1414 EraseElementPinsAndPads (ElementType *Element)
1416 PIN_LOOP (Element);
1418 ErasePin (pin);
1420 END_LOOP;
1421 PAD_LOOP (Element);
1423 ErasePad (pad);
1425 END_LOOP;
1428 /* ---------------------------------------------------------------------------
1429 * erases the name of an element
1431 void
1432 EraseElementName (ElementType *Element)
1434 if (TEST_FLAG (HIDENAMEFLAG, Element))
1435 return;
1436 DrawText (NULL, &ELEMENT_TEXT (PCB, Element));
1440 void
1441 EraseObject (int type, void *lptr, void *ptr)
1443 switch (type)
1445 case VIA_TYPE:
1446 case PIN_TYPE:
1447 ErasePin ((PinType *) ptr);
1448 break;
1449 case TEXT_TYPE:
1450 case ELEMENTNAME_TYPE:
1451 EraseText ((LayerType *)lptr, (TextType *) ptr);
1452 break;
1453 case POLYGON_TYPE:
1454 ErasePolygon ((PolygonType *) ptr);
1455 break;
1456 case ELEMENT_TYPE:
1457 EraseElement ((ElementType *) ptr);
1458 break;
1459 case LINE_TYPE:
1460 case ELEMENTLINE_TYPE:
1461 case RATLINE_TYPE:
1462 EraseLine ((LineType *) ptr);
1463 break;
1464 case PAD_TYPE:
1465 ErasePad ((PadType *) ptr);
1466 break;
1467 case ARC_TYPE:
1468 case ELEMENTARC_TYPE:
1469 EraseArc ((ArcType *) ptr);
1470 break;
1471 default:
1472 Message ("hace: Internal ERROR, trying to erase an unknown type\n");
1478 void
1479 DrawObject (int type, void *ptr1, void *ptr2)
1481 switch (type)
1483 case VIA_TYPE:
1484 if (PCB->ViaOn)
1485 DrawVia ((PinType *) ptr2);
1486 break;
1487 case LINE_TYPE:
1488 if (((LayerType *) ptr1)->On)
1489 DrawLine ((LayerType *) ptr1, (LineType *) ptr2);
1490 break;
1491 case ARC_TYPE:
1492 if (((LayerType *) ptr1)->On)
1493 DrawArc ((LayerType *) ptr1, (ArcType *) ptr2);
1494 break;
1495 case TEXT_TYPE:
1496 if (((LayerType *) ptr1)->On)
1497 DrawText ((LayerType *) ptr1, (TextType *) ptr2);
1498 break;
1499 case POLYGON_TYPE:
1500 if (((LayerType *) ptr1)->On)
1501 DrawPolygon ((LayerType *) ptr1, (PolygonType *) ptr2);
1502 break;
1503 case ELEMENT_TYPE:
1504 if (PCB->ElementOn &&
1505 (FRONT ((ElementType *) ptr2) || PCB->InvisibleObjectsOn))
1506 DrawElement ((ElementType *) ptr2);
1507 break;
1508 case RATLINE_TYPE:
1509 if (PCB->RatOn)
1510 DrawRat ((RatType *) ptr2);
1511 break;
1512 case PIN_TYPE:
1513 if (PCB->PinOn)
1514 DrawPin ((PinType *) ptr2);
1515 break;
1516 case PAD_TYPE:
1517 if (PCB->PinOn)
1518 DrawPad ((PadType *) ptr2);
1519 break;
1520 case ELEMENTNAME_TYPE:
1521 if (PCB->ElementOn &&
1522 (FRONT ((ElementType *) ptr2) || PCB->InvisibleObjectsOn))
1523 DrawElementName ((ElementType *) ptr1);
1524 break;
1528 static void
1529 draw_element (ElementType *element)
1531 draw_element_package (element);
1532 draw_element_name (element);
1533 draw_element_pins_and_pads (element);
1536 /* ---------------------------------------------------------------------------
1537 * HID drawing callback.
1540 void
1541 hid_expose_callback (HID * hid, BoxType * region, void *item)
1543 HID *old_gui = gui;
1545 gui = hid;
1546 Output.fgGC = gui->graphics->make_gc ();
1547 Output.bgGC = gui->graphics->make_gc ();
1548 Output.pmGC = gui->graphics->make_gc ();
1550 hid->graphics->set_color (Output.pmGC, "erase");
1551 hid->graphics->set_color (Output.bgGC, "drill");
1553 if (item)
1555 doing_pinout = true;
1556 draw_element ((ElementType *)item);
1557 doing_pinout = false;
1559 else
1560 DrawEverything (region);
1562 gui->graphics->destroy_gc (Output.fgGC);
1563 gui->graphics->destroy_gc (Output.bgGC);
1564 gui->graphics->destroy_gc (Output.pmGC);
1565 gui = old_gui;