src/undo.c: Converted plain comments into doxygen comments.
[geda-pcb/pcjc2.git] / src / draw.c
blob00966af7562099706e3c60125324cd999874602a
1 /*!
2 * \file src/draw.c
4 * \brief Drawing routines.
6 * <hr>
8 * <h1><b>Copyright.</b></h1>\n
10 * PCB, interactive printed circuit board design
12 * Copyright (C) 1994,1995,1996, 2003, 2004 Thomas Nau
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 * Contact addresses for paper mail and Email:
29 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
30 * Thomas.Nau@rz.uni-ulm.de
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
37 #include "global.h"
38 #include "hid_draw.h"
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"
54 #ifdef HAVE_LIBDMALLOC
55 #include <dmalloc.h>
56 #endif
58 #undef NDEBUG
59 #include <assert.h>
61 #ifndef MAXINT
62 #define MAXINT (((unsigned int)(~0))>>1)
63 #endif
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
72 /* ---------------------------------------------------------------------------
73 * some local identifiers
75 static BoxType Block = {MAXINT, MAXINT, -MAXINT, -MAXINT};
77 static int doing_pinout = 0;
78 static bool doing_assy = false;
80 /* ---------------------------------------------------------------------------
81 * some local prototypes
83 static void DrawEverything (const BoxType *);
84 static void DrawPPV (int group, const BoxType *);
85 static void AddPart (void *);
86 static void DrawEMark (ElementType *, Coord, Coord, bool);
87 static void DrawRats (const BoxType *);
89 static void
90 set_object_color (AnyObjectType *obj, char *warn_color, char *selected_color,
91 char *connected_color, char *found_color, char *normal_color)
93 char *color;
95 if (warn_color != NULL && TEST_FLAG (WARNFLAG, obj)) color = warn_color;
96 else if (selected_color != NULL && TEST_FLAG (SELECTEDFLAG, obj)) color = selected_color;
97 else if (connected_color != NULL && TEST_FLAG (CONNECTEDFLAG, obj)) color = connected_color;
98 else if (found_color != NULL && TEST_FLAG (FOUNDFLAG, obj)) color = found_color;
99 else color = normal_color;
101 gui->graphics->set_color (Output.fgGC, color);
104 static void
105 set_layer_object_color (LayerType *layer, AnyObjectType *obj)
107 set_object_color (obj, NULL, layer->SelectedColor, PCB->ConnectedColor, PCB->FoundColor, layer->Color);
111 * \brief Adds the update rect to the update region.
113 static void
114 AddPart (void *b)
116 BoxType *box = (BoxType *) b;
118 Block.X1 = MIN (Block.X1, box->X1);
119 Block.X2 = MAX (Block.X2, box->X2);
120 Block.Y1 = MIN (Block.Y1, box->Y1);
121 Block.Y2 = MAX (Block.Y2, box->Y2);
125 * \brief Initiate the actual redrawing of the updated area.
127 void
128 Draw (void)
130 if (Block.X1 <= Block.X2 && Block.Y1 <= Block.Y2)
131 gui->invalidate_lr (Block.X1, Block.X2, Block.Y1, Block.Y2);
133 /* shrink the update block */
134 Block.X1 = Block.Y1 = MAXINT;
135 Block.X2 = Block.Y2 = -MAXINT;
139 * \brief Redraws all the data by the event handlers.
141 void
142 Redraw (void)
144 gui->invalidate_all ();
147 static void
148 _draw_pv_name (PinType *pv)
150 BoxType box;
151 bool vert;
152 TextType text;
154 if (!pv->Name || !pv->Name[0])
155 text.TextString = EMPTY (pv->Number);
156 else
157 text.TextString = EMPTY (TEST_FLAG (SHOWNUMBERFLAG, PCB) ? pv->Number : pv->Name);
159 vert = TEST_FLAG (EDGE2FLAG, pv);
161 if (vert)
163 box.X1 = pv->X - pv->Thickness / 2 + Settings.PinoutTextOffsetY;
164 box.Y1 = pv->Y - pv->DrillingHole / 2 - Settings.PinoutTextOffsetX;
166 else
168 box.X1 = pv->X + pv->DrillingHole / 2 + Settings.PinoutTextOffsetX;
169 box.Y1 = pv->Y - pv->Thickness / 2 + Settings.PinoutTextOffsetY;
172 gui->graphics->set_color (Output.fgGC, PCB->PinNameColor);
174 text.Flags = NoFlags ();
175 /* Set font height to approx 56% of pin thickness */
176 text.Scale = 56 * pv->Thickness / FONT_CAPHEIGHT;
177 text.X = box.X1;
178 text.Y = box.Y1;
179 text.Direction = vert ? 1 : 0;
181 if (gui->gui)
182 doing_pinout++;
183 gui->graphics->draw_pcb_text (Output.fgGC, &text, 0);
184 if (gui->gui)
185 doing_pinout--;
188 static void
189 _draw_pv (PinType *pv, bool draw_hole)
191 if (TEST_FLAG (THINDRAWFLAG, PCB))
192 gui->graphics->thindraw_pcb_pv (Output.fgGC, Output.fgGC, pv, draw_hole, false);
193 else
194 gui->graphics->fill_pcb_pv (Output.fgGC, Output.bgGC, pv, draw_hole, false);
196 if ((!TEST_FLAG (HOLEFLAG, pv) && TEST_FLAG (DISPLAYNAMEFLAG, pv)) || doing_pinout)
197 _draw_pv_name (pv);
200 static void
201 draw_pin (PinType *pin, bool draw_hole)
203 if (doing_pinout)
204 gui->graphics->set_color (Output.fgGC, PCB->PinColor);
205 else
206 set_object_color ((AnyObjectType *)pin,
207 PCB->WarnColor, PCB->PinSelectedColor,
208 PCB->ConnectedColor, PCB->FoundColor, PCB->PinColor);
210 _draw_pv (pin, draw_hole);
213 static int
214 pin_callback (const BoxType * b, void *cl)
216 draw_pin ((PinType *)b, false);
217 return 1;
220 static void
221 draw_via (PinType *via, bool draw_hole)
223 if (doing_pinout)
224 gui->graphics->set_color (Output.fgGC, PCB->ViaColor);
225 else
226 set_object_color ((AnyObjectType *)via,
227 PCB->WarnColor, PCB->ViaSelectedColor,
228 PCB->ConnectedColor, PCB->FoundColor, PCB->ViaColor);
230 _draw_pv (via, draw_hole);
233 static int
234 via_callback (const BoxType * b, void *cl)
236 draw_via ((PinType *)b, false);
237 return 1;
240 static void
241 draw_pad_name (PadType *pad)
243 BoxType box;
244 bool vert;
245 TextType text;
247 if (!pad->Name || !pad->Name[0])
248 text.TextString = EMPTY (pad->Number);
249 else
250 text.TextString = EMPTY (TEST_FLAG (SHOWNUMBERFLAG, PCB) ? pad->Number : pad->Name);
252 /* should text be vertical ? */
253 vert = (pad->Point1.X == pad->Point2.X);
255 if (vert)
257 box.X1 = pad->Point1.X - pad->Thickness / 2;
258 box.Y1 = MAX (pad->Point1.Y, pad->Point2.Y) + pad->Thickness / 2;
259 box.X1 += Settings.PinoutTextOffsetY;
260 box.Y1 -= Settings.PinoutTextOffsetX;
262 else
264 box.X1 = MIN (pad->Point1.X, pad->Point2.X) - pad->Thickness / 2;
265 box.Y1 = pad->Point1.Y - pad->Thickness / 2;
266 box.X1 += Settings.PinoutTextOffsetX;
267 box.Y1 += Settings.PinoutTextOffsetY;
270 gui->graphics->set_color (Output.fgGC, PCB->PinNameColor);
272 text.Flags = NoFlags ();
273 /* Set font height to approx 90% of pin thickness */
274 text.Scale = 90 * pad->Thickness / FONT_CAPHEIGHT;
275 text.X = box.X1;
276 text.Y = box.Y1;
277 text.Direction = vert ? 1 : 0;
279 gui->graphics->draw_pcb_text (Output.fgGC, &text, 0);
282 static void
283 _draw_pad (hidGC gc, PadType *pad, bool clear, bool mask)
285 if (clear && !mask && pad->Clearance <= 0)
286 return;
288 if (TEST_FLAG (THINDRAWFLAG, PCB) ||
289 (clear && TEST_FLAG (THINDRAWPOLYFLAG, PCB)))
290 gui->graphics->thindraw_pcb_pad (gc, pad, clear, mask);
291 else
292 gui->graphics->fill_pcb_pad (gc, pad, clear, mask);
295 static void
296 draw_pad (PadType *pad)
298 if (doing_pinout)
299 gui->graphics->set_color (Output.fgGC, PCB->PinColor);
300 else
301 set_object_color ((AnyObjectType *)pad, PCB->WarnColor,
302 PCB->PinSelectedColor, PCB->ConnectedColor, PCB->FoundColor,
303 FRONT (pad) ? PCB->PinColor : PCB->InvisibleObjectsColor);
305 _draw_pad (Output.fgGC, pad, false, false);
307 if (doing_pinout || TEST_FLAG (DISPLAYNAMEFLAG, pad))
308 draw_pad_name (pad);
311 static int
312 pad_callback (const BoxType * b, void *cl)
314 PadType *pad = (PadType *) b;
315 int *side = cl;
317 if (ON_SIDE (pad, *side))
318 draw_pad (pad);
319 return 1;
322 static void
323 draw_element_name (ElementType *element)
325 if ((TEST_FLAG (HIDENAMESFLAG, PCB) && gui->gui) ||
326 TEST_FLAG (HIDENAMEFLAG, element))
327 return;
328 if (doing_pinout || doing_assy)
329 gui->graphics->set_color (Output.fgGC, PCB->ElementColor);
330 else if (TEST_FLAG (SELECTEDFLAG, &ELEMENT_TEXT (PCB, element)))
331 gui->graphics->set_color (Output.fgGC, PCB->ElementSelectedColor);
332 else if (FRONT (element))
333 gui->graphics->set_color (Output.fgGC, PCB->ElementColor);
334 else
335 gui->graphics->set_color (Output.fgGC, PCB->InvisibleObjectsColor);
336 gui->graphics->draw_pcb_text (Output.fgGC, &ELEMENT_TEXT (PCB, element), PCB->minSlk);
339 static int
340 name_callback (const BoxType * b, void *cl)
342 TextType *text = (TextType *) b;
343 ElementType *element = (ElementType *) text->Element;
344 int *side = cl;
346 if (TEST_FLAG (HIDENAMEFLAG, element))
347 return 0;
349 if (ON_SIDE (element, *side))
350 draw_element_name (element);
351 return 0;
354 static void
355 draw_element_pins_and_pads (ElementType *element)
357 PAD_LOOP (element);
359 if (doing_pinout || doing_assy || FRONT (pad) || PCB->InvisibleObjectsOn)
360 draw_pad (pad);
362 END_LOOP;
363 PIN_LOOP (element);
365 draw_pin (pin, true);
367 END_LOOP;
370 static int
371 EMark_callback (const BoxType * b, void *cl)
373 ElementType *element = (ElementType *) b;
375 DrawEMark (element, element->MarkX, element->MarkY, !FRONT (element));
376 return 1;
379 static int
380 hole_callback (const BoxType * b, void *cl)
382 PinType *pv = (PinType *) b;
383 int plated = cl ? *(int *) cl : -1;
385 if ((plated == 0 && !TEST_FLAG (HOLEFLAG, pv)) ||
386 (plated == 1 && TEST_FLAG (HOLEFLAG, pv)))
387 return 1;
389 if (TEST_FLAG (THINDRAWFLAG, PCB))
391 if (!TEST_FLAG (HOLEFLAG, pv))
393 gui->graphics->set_line_cap (Output.fgGC, Round_Cap);
394 gui->graphics->set_line_width (Output.fgGC, 0);
395 gui->graphics->draw_arc (Output.fgGC,
396 pv->X, pv->Y, pv->DrillingHole / 2,
397 pv->DrillingHole / 2, 0, 360);
400 else
401 gui->graphics->fill_circle (Output.bgGC, pv->X, pv->Y, pv->DrillingHole / 2);
403 if (TEST_FLAG (HOLEFLAG, pv))
405 set_object_color ((AnyObjectType *) pv,
406 PCB->WarnColor, PCB->ViaSelectedColor,
407 NULL, NULL, Settings.BlackColor);
409 gui->graphics->set_line_cap (Output.fgGC, Round_Cap);
410 gui->graphics->set_line_width (Output.fgGC, 0);
411 gui->graphics->draw_arc (Output.fgGC,
412 pv->X, pv->Y, pv->DrillingHole / 2,
413 pv->DrillingHole / 2, 0, 360);
415 return 1;
418 void
419 DrawHoles (bool draw_plated, bool draw_unplated, const BoxType *drawn_area)
421 int plated = -1;
423 if ( draw_plated && !draw_unplated) plated = 1;
424 if (!draw_plated && draw_unplated) plated = 0;
426 r_search (PCB->Data->pin_tree, drawn_area, NULL, hole_callback, &plated);
427 r_search (PCB->Data->via_tree, drawn_area, NULL, hole_callback, &plated);
430 static int
431 line_callback (const BoxType * b, void *cl)
433 LayerType *layer = (LayerType *) cl;
434 LineType *line = (LineType *) b;
436 set_layer_object_color (layer, (AnyObjectType *) line);
437 gui->graphics->draw_pcb_line (Output.fgGC, line);
439 return 1;
442 static int
443 rat_callback (const BoxType * b, void *cl)
445 RatType *rat = (RatType *)b;
447 set_object_color ((AnyObjectType *) rat, NULL, PCB->RatSelectedColor,
448 PCB->ConnectedColor, PCB->FoundColor, PCB->RatColor);
450 if (Settings.RatThickness < 100)
451 rat->Thickness = pixel_slop * Settings.RatThickness;
452 /* rats.c set VIAFLAG if this rat goes to a containing poly: draw a donut */
453 if (TEST_FLAG(VIAFLAG, rat))
455 int w = rat->Thickness;
457 if (TEST_FLAG (THINDRAWFLAG, PCB))
458 gui->graphics->set_line_width (Output.fgGC, 0);
459 else
460 gui->graphics->set_line_width (Output.fgGC, w);
461 gui->graphics->draw_arc (Output.fgGC, rat->Point1.X, rat->Point1.Y,
462 w * 2, w * 2, 0, 360);
464 else
465 gui->graphics->draw_pcb_line (Output.fgGC, (LineType *) rat);
466 return 1;
469 static int
470 arc_callback (const BoxType * b, void *cl)
472 LayerType *layer = (LayerType *) cl;
473 ArcType *arc = (ArcType *) b;
475 set_layer_object_color (layer, (AnyObjectType *) arc);
476 gui->graphics->draw_pcb_arc (Output.fgGC, arc);
478 return 1;
481 static void
482 draw_element_package (ElementType *element)
484 /* set color and draw lines, arcs, text and pins */
485 if (doing_pinout || doing_assy)
486 gui->graphics->set_color (Output.fgGC, PCB->ElementColor);
487 else if (TEST_FLAG (SELECTEDFLAG, element))
488 gui->graphics->set_color (Output.fgGC, PCB->ElementSelectedColor);
489 else if (FRONT (element))
490 gui->graphics->set_color (Output.fgGC, PCB->ElementColor);
491 else
492 gui->graphics->set_color (Output.fgGC, PCB->InvisibleObjectsColor);
494 /* draw lines, arcs, text and pins */
495 ELEMENTLINE_LOOP (element);
497 gui->graphics->draw_pcb_line (Output.fgGC, line);
499 END_LOOP;
500 ARC_LOOP (element);
502 gui->graphics->draw_pcb_arc (Output.fgGC, arc);
504 END_LOOP;
507 static int
508 element_callback (const BoxType * b, void *cl)
510 ElementType *element = (ElementType *) b;
511 int *side = cl;
513 if (ON_SIDE (element, *side))
514 draw_element_package (element);
515 return 1;
519 * \brief Prints assembly drawing.
521 void
522 PrintAssembly (int side, const BoxType * drawn_area)
524 int side_group = GetLayerGroupNumberBySide (side);
526 doing_assy = true;
527 gui->graphics->set_draw_faded (Output.fgGC, 1);
528 DrawLayerGroup (side_group, drawn_area);
529 gui->graphics->set_draw_faded (Output.fgGC, 0);
531 /* draw package */
532 DrawSilk (side, drawn_area);
533 doing_assy = false;
537 * \brief Initializes some identifiers for a new zoom factor and redraws
538 * whole screen.
540 static void
541 DrawEverything (const BoxType *drawn_area)
543 int i, ngroups, side;
544 int top_group, bottom_group;
545 /* This is the list of layer groups we will draw. */
546 int do_group[MAX_GROUP];
547 /* This is the reverse of the order in which we draw them. */
548 int drawn_groups[MAX_GROUP];
549 int plated, unplated;
550 bool paste_empty;
552 PCB->Data->SILKLAYER.Color = PCB->ElementColor;
553 PCB->Data->BACKSILKLAYER.Color = PCB->InvisibleObjectsColor;
555 memset (do_group, 0, sizeof (do_group));
556 for (ngroups = 0, i = 0; i < max_copper_layer; i++)
558 LayerType *l = LAYER_ON_STACK (i);
559 int group = GetLayerGroupNumberByNumber (LayerStack[i]);
560 if (l->On && !do_group[group])
562 do_group[group] = 1;
563 drawn_groups[ngroups++] = group;
567 top_group = GetLayerGroupNumberBySide (TOP_SIDE);
568 bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
571 * first draw all 'invisible' stuff
573 if (!TEST_FLAG (CHECKPLANESFLAG, PCB)
574 && gui->set_layer ("invisible", SL (INVISIBLE, 0), 0))
576 side = SWAP_IDENT ? TOP_SIDE : BOTTOM_SIDE;
577 if (PCB->ElementOn)
579 r_search (PCB->Data->element_tree, drawn_area, NULL, element_callback, &side);
580 r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], drawn_area, NULL, name_callback, &side);
581 DrawLayer (&(PCB->Data->Layer[max_copper_layer + side]), drawn_area);
583 r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side);
584 gui->end_layer ();
587 /* draw all layers in layerstack order */
588 for (i = ngroups - 1; i >= 0; i--)
590 int group = drawn_groups[i];
592 if (gui->set_layer (0, group, 0))
594 DrawLayerGroup (group, drawn_area);
595 gui->end_layer ();
599 if (TEST_FLAG (CHECKPLANESFLAG, PCB) && gui->gui)
600 return;
602 /* Draw pins, pads, vias below silk */
603 if (gui->gui)
604 DrawPPV (SWAP_IDENT ? bottom_group : top_group, drawn_area);
605 else
607 CountHoles (&plated, &unplated, drawn_area);
609 if (plated && gui->set_layer ("plated-drill", SL (PDRILL, 0), 0))
611 DrawHoles (true, false, drawn_area);
612 gui->end_layer ();
615 if (unplated && gui->set_layer ("unplated-drill", SL (UDRILL, 0), 0))
617 DrawHoles (false, true, drawn_area);
618 gui->end_layer ();
622 /* Draw the solder mask if turned on */
623 if (gui->set_layer ("componentmask", SL (MASK, TOP), 0))
625 DrawMask (TOP_SIDE, drawn_area);
626 gui->end_layer ();
629 if (gui->set_layer ("soldermask", SL (MASK, BOTTOM), 0))
631 DrawMask (BOTTOM_SIDE, drawn_area);
632 gui->end_layer ();
635 if (gui->set_layer ("topsilk", SL (SILK, TOP), 0))
637 DrawSilk (TOP_SIDE, drawn_area);
638 gui->end_layer ();
641 if (gui->set_layer ("bottomsilk", SL (SILK, BOTTOM), 0))
643 DrawSilk (BOTTOM_SIDE, drawn_area);
644 gui->end_layer ();
647 if (gui->gui)
649 /* Draw element Marks */
650 if (PCB->PinOn)
651 r_search (PCB->Data->element_tree, drawn_area, NULL, EMark_callback,
652 NULL);
653 /* Draw rat lines on top */
654 if (gui->set_layer ("rats", SL (RATS, 0), 0))
656 DrawRats(drawn_area);
657 gui->end_layer ();
661 paste_empty = IsPasteEmpty (TOP_SIDE);
662 if (gui->set_layer ("toppaste", SL (PASTE, TOP), paste_empty))
664 DrawPaste (TOP_SIDE, drawn_area);
665 gui->end_layer ();
668 paste_empty = IsPasteEmpty (BOTTOM_SIDE);
669 if (gui->set_layer ("bottompaste", SL (PASTE, BOTTOM), paste_empty))
671 DrawPaste (BOTTOM_SIDE, drawn_area);
672 gui->end_layer ();
675 if (gui->set_layer ("topassembly", SL (ASSY, TOP), 0))
677 PrintAssembly (TOP_SIDE, drawn_area);
678 gui->end_layer ();
681 if (gui->set_layer ("bottomassembly", SL (ASSY, BOTTOM), 0))
683 PrintAssembly (BOTTOM_SIDE, drawn_area);
684 gui->end_layer ();
687 if (gui->set_layer ("fab", SL (FAB, 0), 0))
689 PrintFab (Output.fgGC);
690 gui->end_layer ();
694 static void
695 DrawEMark (ElementType *e, Coord X, Coord Y, bool invisible)
697 Coord mark_size = EMARK_SIZE;
698 if (!PCB->InvisibleObjectsOn && invisible)
699 return;
701 if (e->Pin != NULL)
703 PinType *pin0 = e->Pin->data;
704 if (TEST_FLAG (HOLEFLAG, pin0))
705 mark_size = MIN (mark_size, pin0->DrillingHole / 2);
706 else
707 mark_size = MIN (mark_size, pin0->Thickness / 2);
710 if (e->Pad != NULL)
712 PadType *pad0 = e->Pad->data;
713 mark_size = MIN (mark_size, pad0->Thickness / 2);
716 gui->graphics->set_color (Output.fgGC,
717 invisible ? PCB->InvisibleMarkColor : PCB->ElementColor);
718 gui->graphics->set_line_cap (Output.fgGC, Trace_Cap);
719 gui->graphics->set_line_width (Output.fgGC, 0);
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);
722 gui->graphics->draw_line (Output.fgGC, X - mark_size, Y, X, Y + mark_size);
723 gui->graphics->draw_line (Output.fgGC, X + mark_size, Y, X, Y + mark_size);
726 * If an element is locked, place a "L" on top of the "diamond".
727 * This provides a nice visual indication that it is locked that
728 * works even for color blind users.
730 if (TEST_FLAG (LOCKFLAG, e) )
732 gui->graphics->draw_line (Output.fgGC, X, Y, X + 2 * mark_size, Y);
733 gui->graphics->draw_line (Output.fgGC, X, Y, X, Y - 4* mark_size);
738 * \brief Draws pins pads and vias - Always draws for non-gui HIDs,
739 * otherwise drawing depends on PCB->PinOn and PCB->ViaOn.
741 static void
742 DrawPPV (int group, const BoxType *drawn_area)
744 int top_group = GetLayerGroupNumberBySide (TOP_SIDE);
745 int bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
746 int side;
748 if (PCB->PinOn || !gui->gui)
750 /* draw element pins */
751 r_search (PCB->Data->pin_tree, drawn_area, NULL, pin_callback, NULL);
753 /* draw element pads */
754 if (group == top_group)
756 side = TOP_SIDE;
757 r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side);
760 if (group == bottom_group)
762 side = BOTTOM_SIDE;
763 r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side);
767 /* draw vias */
768 if (PCB->ViaOn || !gui->gui)
770 r_search (PCB->Data->via_tree, drawn_area, NULL, via_callback, NULL);
771 r_search (PCB->Data->via_tree, drawn_area, NULL, hole_callback, NULL);
773 if (PCB->PinOn || doing_assy)
774 r_search (PCB->Data->pin_tree, drawn_area, NULL, hole_callback, NULL);
777 static int
778 clearPin_callback (const BoxType * b, void *cl)
780 PinType *pin = (PinType *) b;
781 if (TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG (THINDRAWPOLYFLAG, PCB))
782 gui->graphics->thindraw_pcb_pv (Output.pmGC, Output.pmGC, pin, false, true);
783 else
784 gui->graphics->fill_pcb_pv (Output.pmGC, Output.pmGC, pin, false, true);
785 return 1;
788 struct poly_info {
789 const BoxType *drawn_area;
790 LayerType *layer;
793 static int
794 poly_callback (const BoxType * b, void *cl)
796 struct poly_info *i = cl;
797 PolygonType *polygon = (PolygonType *)b;
799 set_layer_object_color (i->layer, (AnyObjectType *) polygon);
801 gui->graphics->draw_pcb_polygon (Output.fgGC, polygon, i->drawn_area);
803 return 1;
806 static int
807 clearPad_callback (const BoxType * b, void *cl)
809 PadType *pad = (PadType *) b;
810 int *side = cl;
811 if (ON_SIDE (pad, *side) && pad->Mask)
812 _draw_pad (Output.pmGC, pad, true, true);
813 return 1;
817 * \brief Draws silk layer.
819 void
820 DrawSilk (int side, const BoxType * drawn_area)
822 #if 0
823 /* This code is used when you want to mask silk to avoid exposed
824 pins and pads. We decided it was a bad idea to do this
825 unconditionally, but the code remains. */
826 #endif
828 #if 0
829 if (gui->poly_before)
831 gui->graphics->use_mask (HID_MASK_BEFORE);
832 #endif
833 DrawLayer (LAYER_PTR (max_copper_layer + side), drawn_area);
834 /* draw package */
835 r_search (PCB->Data->element_tree, drawn_area, NULL, element_callback, &side);
836 r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], drawn_area, NULL, name_callback, &side);
837 #if 0
840 gui->graphics->use_mask (HID_MASK_CLEAR);
841 r_search (PCB->Data->pin_tree, drawn_area, NULL, clearPin_callback, NULL);
842 r_search (PCB->Data->via_tree, drawn_area, NULL, clearPin_callback, NULL);
843 r_search (PCB->Data->pad_tree, drawn_area, NULL, clearPad_callback, &side);
845 if (gui->poly_after)
847 gui->graphics->use_mask (HID_MASK_AFTER);
848 DrawLayer (LAYER_PTR (max_copper_layer + layer), drawn_area);
849 /* draw package */
850 r_search (PCB->Data->element_tree, drawn_area, NULL, element_callback, &side);
851 r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], drawn_area, NULL, name_callback, &side);
853 gui->graphics->use_mask (HID_MASK_OFF);
854 #endif
858 static void
859 DrawMaskBoardArea (int mask_type, const BoxType *drawn_area)
861 /* Skip the mask drawing if the GUI doesn't want this type */
862 if ((mask_type == HID_MASK_BEFORE && !gui->poly_before) ||
863 (mask_type == HID_MASK_AFTER && !gui->poly_after))
864 return;
866 gui->graphics->use_mask (mask_type);
867 gui->graphics->set_color (Output.fgGC, PCB->MaskColor);
868 if (drawn_area == NULL)
869 gui->graphics->fill_rect (Output.fgGC, 0, 0, PCB->MaxWidth, PCB->MaxHeight);
870 else
871 gui->graphics->fill_rect (Output.fgGC, drawn_area->X1, drawn_area->Y1,
872 drawn_area->X2, drawn_area->Y2);
876 * \brief Draws solder mask layer - this will cover nearly everything.
878 void
879 DrawMask (int side, const BoxType *screen)
881 int thin = TEST_FLAG(THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB);
883 if (thin)
884 gui->graphics->set_color (Output.pmGC, PCB->MaskColor);
885 else
887 DrawMaskBoardArea (HID_MASK_BEFORE, screen);
888 gui->graphics->use_mask (HID_MASK_CLEAR);
891 r_search (PCB->Data->pin_tree, screen, NULL, clearPin_callback, NULL);
892 r_search (PCB->Data->via_tree, screen, NULL, clearPin_callback, NULL);
893 r_search (PCB->Data->pad_tree, screen, NULL, clearPad_callback, &side);
895 if (thin)
896 gui->graphics->set_color (Output.pmGC, "erase");
897 else
899 DrawMaskBoardArea (HID_MASK_AFTER, screen);
900 gui->graphics->use_mask (HID_MASK_OFF);
905 * \brief Draws solder paste layer for a given side of the board.
907 void
908 DrawPaste (int side, const BoxType *drawn_area)
910 gui->graphics->set_color (Output.fgGC, PCB->ElementColor);
911 ALLPAD_LOOP (PCB->Data);
913 if (ON_SIDE (pad, side) && !TEST_FLAG (NOPASTEFLAG, pad) && pad->Mask > 0)
915 if (pad->Mask < pad->Thickness)
916 _draw_pad (Output.fgGC, pad, true, true);
917 else
918 _draw_pad (Output.fgGC, pad, false, false);
921 ENDALL_LOOP;
924 static void
925 DrawRats (const BoxType *drawn_area)
928 * XXX lesstif allows positive AND negative drawing in HID_MASK_CLEAR.
929 * XXX gtk only allows negative drawing.
930 * XXX using the mask here is to get rat transparency
932 int can_mask = strcmp(gui->name, "lesstif") == 0;
934 if (can_mask)
935 gui->graphics->use_mask (HID_MASK_CLEAR);
936 r_search (PCB->Data->rat_tree, drawn_area, NULL, rat_callback, NULL);
937 if (can_mask)
938 gui->graphics->use_mask (HID_MASK_OFF);
941 static int
942 text_callback (const BoxType * b, void *cl)
944 LayerType *layer = cl;
945 TextType *text = (TextType *)b;
946 int min_silk_line;
948 if (TEST_FLAG (SELECTEDFLAG, text))
949 gui->graphics->set_color (Output.fgGC, layer->SelectedColor);
950 else
951 gui->graphics->set_color (Output.fgGC, layer->Color);
952 if (layer == &PCB->Data->SILKLAYER ||
953 layer == &PCB->Data->BACKSILKLAYER)
954 min_silk_line = PCB->minSlk;
955 else
956 min_silk_line = PCB->minWid;
957 gui->graphics->draw_pcb_text (Output.fgGC, text, min_silk_line);
958 return 1;
961 void
962 DrawLayer (LayerType *Layer, const BoxType *screen)
964 struct poly_info info = {screen, Layer};
966 /* print the non-clearing polys */
967 r_search (Layer->polygon_tree, screen, NULL, poly_callback, &info);
969 if (TEST_FLAG (CHECKPLANESFLAG, PCB))
970 return;
972 /* draw all visible lines this layer */
973 r_search (Layer->line_tree, screen, NULL, line_callback, Layer);
975 /* draw the layer arcs on screen */
976 r_search (Layer->arc_tree, screen, NULL, arc_callback, Layer);
978 /* draw the layer text on screen */
979 r_search (Layer->text_tree, screen, NULL, text_callback, Layer);
981 /* We should check for gui->gui here, but it's kinda cool seeing the
982 auto-outline magically disappear when you first add something to
983 the "outline" layer. */
984 if (IsLayerEmpty (Layer)
985 && (strcmp (Layer->Name, "outline") == 0
986 || strcmp (Layer->Name, "route") == 0))
988 gui->graphics->set_color (Output.fgGC, Layer->Color);
989 gui->graphics->set_line_width (Output.fgGC, PCB->minWid);
990 gui->graphics->draw_rect (Output.fgGC,
991 0, 0,
992 PCB->MaxWidth, PCB->MaxHeight);
997 * \brief Draws one layer group.
999 * If the exporter is not a GUI, also draws the pins / pads / vias in
1000 * this layer group.
1002 void
1003 DrawLayerGroup (int group, const BoxType *drawn_area)
1005 int i, rv = 1;
1006 int layernum;
1007 LayerType *Layer;
1008 int n_entries = PCB->LayerGroups.Number[group];
1009 Cardinal *layers = PCB->LayerGroups.Entries[group];
1011 for (i = n_entries - 1; i >= 0; i--)
1013 layernum = layers[i];
1014 Layer = PCB->Data->Layer + layers[i];
1015 if (strcmp (Layer->Name, "outline") == 0 ||
1016 strcmp (Layer->Name, "route") == 0)
1017 rv = 0;
1018 if (layernum < max_copper_layer && Layer->On)
1019 DrawLayer (Layer, drawn_area);
1021 if (n_entries > 1)
1022 rv = 1;
1024 if (rv && !gui->gui)
1025 DrawPPV (group, drawn_area);
1028 static void
1029 GatherPVName (PinType *Ptr)
1031 BoxType box;
1032 bool vert = TEST_FLAG (EDGE2FLAG, Ptr);
1034 if (vert)
1036 box.X1 = Ptr->X - Ptr->Thickness / 2 + Settings.PinoutTextOffsetY;
1037 box.Y1 = Ptr->Y - Ptr->DrillingHole / 2 - Settings.PinoutTextOffsetX;
1039 else
1041 box.X1 = Ptr->X + Ptr->DrillingHole / 2 + Settings.PinoutTextOffsetX;
1042 box.Y1 = Ptr->Y - Ptr->Thickness / 2 + Settings.PinoutTextOffsetY;
1045 if (vert)
1047 box.X2 = box.X1;
1048 box.Y2 = box.Y1;
1050 else
1052 box.X2 = box.X1;
1053 box.Y2 = box.Y1;
1055 AddPart (&box);
1058 static void
1059 GatherPadName (PadType *Pad)
1061 BoxType box;
1062 bool vert;
1064 /* should text be vertical ? */
1065 vert = (Pad->Point1.X == Pad->Point2.X);
1067 if (vert)
1069 box.X1 = Pad->Point1.X - Pad->Thickness / 2;
1070 box.Y1 = MAX (Pad->Point1.Y, Pad->Point2.Y) + Pad->Thickness / 2;
1071 box.X1 += Settings.PinoutTextOffsetY;
1072 box.Y1 -= Settings.PinoutTextOffsetX;
1073 box.X2 = box.X1;
1074 box.Y2 = box.Y1;
1076 else
1078 box.X1 = MIN (Pad->Point1.X, Pad->Point2.X) - Pad->Thickness / 2;
1079 box.Y1 = Pad->Point1.Y - Pad->Thickness / 2;
1080 box.X1 += Settings.PinoutTextOffsetX;
1081 box.Y1 += Settings.PinoutTextOffsetY;
1082 box.X2 = box.X1;
1083 box.Y2 = box.Y1;
1086 AddPart (&box);
1087 return;
1091 * \brief Draw a via object.
1093 void
1094 DrawVia (PinType *Via)
1096 AddPart (Via);
1097 if (!TEST_FLAG (HOLEFLAG, Via) && TEST_FLAG (DISPLAYNAMEFLAG, Via))
1098 DrawViaName (Via);
1102 * \brief Draws the name of a via.
1104 void
1105 DrawViaName (PinType *Via)
1107 GatherPVName (Via);
1111 * \brief Draw a pin object.
1113 void
1114 DrawPin (PinType *Pin)
1116 AddPart (Pin);
1117 if ((!TEST_FLAG (HOLEFLAG, Pin) && TEST_FLAG (DISPLAYNAMEFLAG, Pin))
1118 || doing_pinout)
1119 DrawPinName (Pin);
1123 * \brief Draws the name of a pin.
1125 void
1126 DrawPinName (PinType *Pin)
1128 GatherPVName (Pin);
1132 * \brief Draw a pad object.
1134 void
1135 DrawPad (PadType *Pad)
1137 AddPart (Pad);
1138 if (doing_pinout || TEST_FLAG (DISPLAYNAMEFLAG, Pad))
1139 DrawPadName (Pad);
1143 * \brief Draws the name of a pad.
1145 void
1146 DrawPadName (PadType *Pad)
1148 GatherPadName (Pad);
1152 * \brief Draws a line on a layer.
1154 void
1155 DrawLine (LayerType *Layer, LineType *Line)
1157 AddPart (Line);
1161 * \brief Draws a ratline.
1163 void
1164 DrawRat (RatType *Rat)
1166 if (Settings.RatThickness < 100)
1167 Rat->Thickness = pixel_slop * Settings.RatThickness;
1168 /* rats.c set VIAFLAG if this rat goes to a containing poly: draw a donut */
1169 if (TEST_FLAG(VIAFLAG, Rat))
1171 Coord w = Rat->Thickness;
1173 BoxType b;
1175 b.X1 = Rat->Point1.X - w * 2 - w / 2;
1176 b.X2 = Rat->Point1.X + w * 2 + w / 2;
1177 b.Y1 = Rat->Point1.Y - w * 2 - w / 2;
1178 b.Y2 = Rat->Point1.Y + w * 2 + w / 2;
1179 AddPart (&b);
1181 else
1182 DrawLine (NULL, (LineType *)Rat);
1186 * \brief Draws an arc on a layer.
1188 void
1189 DrawArc (LayerType *Layer, ArcType *Arc)
1191 AddPart (Arc);
1195 * \brief Draws a text on a layer.
1197 void
1198 DrawText (LayerType *Layer, TextType *Text)
1200 AddPart (Text);
1205 * \brief Draws a polygon on a layer.
1207 void
1208 DrawPolygon (LayerType *Layer, PolygonType *Polygon)
1210 AddPart (Polygon);
1214 * \brief Draws an element.
1216 void
1217 DrawElement (ElementType *Element)
1219 DrawElementPackage (Element);
1220 DrawElementName (Element);
1221 DrawElementPinsAndPads (Element);
1225 * \brief Draws the name of an element.
1227 void
1228 DrawElementName (ElementType *Element)
1230 if (TEST_FLAG (HIDENAMEFLAG, Element))
1231 return;
1232 DrawText (NULL, &ELEMENT_TEXT (PCB, Element));
1236 * \brief Draws the package of an element.
1238 void
1239 DrawElementPackage (ElementType *Element)
1241 ELEMENTLINE_LOOP (Element);
1243 DrawLine (NULL, line);
1245 END_LOOP;
1246 ARC_LOOP (Element);
1248 DrawArc (NULL, arc);
1250 END_LOOP;
1254 * \brief Draw pins of an element.
1256 void
1257 DrawElementPinsAndPads (ElementType *Element)
1259 PAD_LOOP (Element);
1261 if (doing_pinout || doing_assy || FRONT (pad) || PCB->InvisibleObjectsOn)
1262 DrawPad (pad);
1264 END_LOOP;
1265 PIN_LOOP (Element);
1267 DrawPin (pin);
1269 END_LOOP;
1273 * \brief Erase a via.
1275 void
1276 EraseVia (PinType *Via)
1278 AddPart (Via);
1279 if (TEST_FLAG (DISPLAYNAMEFLAG, Via))
1280 EraseViaName (Via);
1284 * \brief Erase a ratline.
1286 void
1287 EraseRat (RatType *Rat)
1289 if (TEST_FLAG(VIAFLAG, Rat))
1291 Coord w = Rat->Thickness;
1293 BoxType b;
1295 b.X1 = Rat->Point1.X - w * 2 - w / 2;
1296 b.X2 = Rat->Point1.X + w * 2 + w / 2;
1297 b.Y1 = Rat->Point1.Y - w * 2 - w / 2;
1298 b.Y2 = Rat->Point1.Y + w * 2 + w / 2;
1299 AddPart (&b);
1301 else
1302 EraseLine ((LineType *)Rat);
1307 * \brief Erase a via name.
1309 void
1310 EraseViaName (PinType *Via)
1312 GatherPVName (Via);
1316 * \brief Erase a pad object.
1318 void
1319 ErasePad (PadType *Pad)
1321 AddPart (Pad);
1322 if (TEST_FLAG (DISPLAYNAMEFLAG, Pad))
1323 ErasePadName (Pad);
1327 * \brief Erase a pad name.
1329 void
1330 ErasePadName (PadType *Pad)
1332 GatherPadName (Pad);
1336 * \brief Erase a pin object.
1338 void
1339 ErasePin (PinType *Pin)
1341 AddPart (Pin);
1342 if (TEST_FLAG (DISPLAYNAMEFLAG, Pin))
1343 ErasePinName (Pin);
1347 * \brief Erase a pin name.
1349 void
1350 ErasePinName (PinType *Pin)
1352 GatherPVName (Pin);
1356 * \brief Erases a line on a layer.
1358 void
1359 EraseLine (LineType *Line)
1361 AddPart (Line);
1365 * \brief Erases an arc on a layer.
1367 void
1368 EraseArc (ArcType *Arc)
1370 if (!Arc->Thickness)
1371 return;
1372 AddPart (Arc);
1376 * \brief Erases a text on a layer.
1378 void
1379 EraseText (LayerType *Layer, TextType *Text)
1381 /* r_delete_entry (Layer->text_tree, (BoxType *) Text); */
1382 AddPart (Text);
1386 * \brief Erases a polygon on a layer.
1388 void
1389 ErasePolygon (PolygonType *Polygon)
1391 AddPart (Polygon);
1395 * \brief Erases an element.
1397 void
1398 EraseElement (ElementType *Element)
1400 ELEMENTLINE_LOOP (Element);
1402 EraseLine (line);
1404 END_LOOP;
1405 ARC_LOOP (Element);
1407 EraseArc (arc);
1409 END_LOOP;
1410 EraseElementName (Element);
1411 EraseElementPinsAndPads (Element);
1415 * \brief Erases all pins and pads of an element.
1417 void
1418 EraseElementPinsAndPads (ElementType *Element)
1420 PIN_LOOP (Element);
1422 ErasePin (pin);
1424 END_LOOP;
1425 PAD_LOOP (Element);
1427 ErasePad (pad);
1429 END_LOOP;
1433 * \brief Erases the name of an element.
1435 void
1436 EraseElementName (ElementType *Element)
1438 if (TEST_FLAG (HIDENAMEFLAG, Element))
1439 return;
1440 EraseText (NULL, &ELEMENT_TEXT (PCB, Element));}
1443 void
1444 EraseObject (int type, void *lptr, void *ptr)
1446 switch (type)
1448 case VIA_TYPE:
1449 case PIN_TYPE:
1450 ErasePin ((PinType *) ptr);
1451 break;
1452 case TEXT_TYPE:
1453 EraseText ((LayerType *)lptr, (TextType *) ptr);
1454 break;
1455 case ELEMENTNAME_TYPE:
1456 EraseElementName ((ElementType *) ptr);
1457 break;
1458 case POLYGON_TYPE:
1459 ErasePolygon ((PolygonType *) ptr);
1460 break;
1461 case ELEMENT_TYPE:
1462 EraseElement ((ElementType *) ptr);
1463 break;
1464 case LINE_TYPE:
1465 case ELEMENTLINE_TYPE:
1466 case RATLINE_TYPE:
1467 EraseLine ((LineType *) ptr);
1468 break;
1469 case PAD_TYPE:
1470 ErasePad ((PadType *) ptr);
1471 break;
1472 case ARC_TYPE:
1473 case ELEMENTARC_TYPE:
1474 EraseArc ((ArcType *) ptr);
1475 break;
1476 default:
1477 Message ("hace: Internal ERROR, trying to erase an unknown type\n");
1483 void
1484 DrawObject (int type, void *ptr1, void *ptr2)
1486 switch (type)
1488 case VIA_TYPE:
1489 if (PCB->ViaOn)
1490 DrawVia ((PinType *) ptr2);
1491 break;
1492 case LINE_TYPE:
1493 if (((LayerType *) ptr1)->On)
1494 DrawLine ((LayerType *) ptr1, (LineType *) ptr2);
1495 break;
1496 case ARC_TYPE:
1497 if (((LayerType *) ptr1)->On)
1498 DrawArc ((LayerType *) ptr1, (ArcType *) ptr2);
1499 break;
1500 case TEXT_TYPE:
1501 if (((LayerType *) ptr1)->On)
1502 DrawText ((LayerType *) ptr1, (TextType *) ptr2);
1503 break;
1504 case POLYGON_TYPE:
1505 if (((LayerType *) ptr1)->On)
1506 DrawPolygon ((LayerType *) ptr1, (PolygonType *) ptr2);
1507 break;
1508 case ELEMENT_TYPE:
1509 if (PCB->ElementOn &&
1510 (FRONT ((ElementType *) ptr2) || PCB->InvisibleObjectsOn))
1511 DrawElement ((ElementType *) ptr2);
1512 break;
1513 case RATLINE_TYPE:
1514 if (PCB->RatOn)
1515 DrawRat ((RatType *) ptr2);
1516 break;
1517 case PIN_TYPE:
1518 if (PCB->PinOn)
1519 DrawPin ((PinType *) ptr2);
1520 break;
1521 case PAD_TYPE:
1522 if (PCB->PinOn)
1523 DrawPad ((PadType *) ptr2);
1524 break;
1525 case ELEMENTNAME_TYPE:
1526 if (PCB->ElementOn &&
1527 (FRONT ((ElementType *) ptr2) || PCB->InvisibleObjectsOn))
1528 DrawElementName ((ElementType *) ptr1);
1529 break;
1533 static void
1534 draw_element (ElementType *element)
1536 draw_element_package (element);
1537 draw_element_name (element);
1538 draw_element_pins_and_pads (element);
1542 * \brief HID drawing callback.
1544 void
1545 hid_expose_callback (HID * hid, BoxType * region, void *item)
1547 HID *old_gui = gui;
1549 gui = hid;
1550 Output.fgGC = gui->graphics->make_gc ();
1551 Output.bgGC = gui->graphics->make_gc ();
1552 Output.pmGC = gui->graphics->make_gc ();
1554 hid->graphics->set_color (Output.pmGC, "erase");
1555 hid->graphics->set_color (Output.bgGC, "drill");
1557 if (item)
1559 doing_pinout = true;
1560 draw_element ((ElementType *)item);
1561 doing_pinout = false;
1563 else
1564 DrawEverything (region);
1566 gui->graphics->destroy_gc (Output.fgGC);
1567 gui->graphics->destroy_gc (Output.bgGC);
1568 gui->graphics->destroy_gc (Output.pmGC);
1569 gui = old_gui;