[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: gEDA-user: DRC UI mockup



On Sun, 2009-03-29 at 16:21 +0100, Peter Clifton wrote:

> NB: Unfortunately, I don't have a lot of time to develop these ideas in
> terms of code at the moment, so don't expect to see this on my branch
> any time soon!

Ok, so I wanted this to fix some DRC problems on a board I was working
with. Since coding tools is _always_ more fun than doing work, I hacked
some proof of concept code until it worked for what I needed. (A list of
violations, and a way to jump to them in arbitrary order).

Screenshot here:

http://www2.eng.cam.ac.uk/~pcjc2/geda/drc_for_real.png

Compare to:
http://www2.eng.cam.ac.uk/~pcjc2/geda/drc_mockup.png

Patch in progress attached.

-- 
Peter Clifton

Electrical Engineering Division,
Engineering Department,
University of Cambridge,
9, JJ Thomson Avenue,
Cambridge
CB3 0FA

Tel: +44 (0)7729 980173 - (No signal in the lab!)
diff --git a/src/Makefile.am b/src/Makefile.am
index 146fbb9..f35a45f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -241,6 +241,8 @@ LIBGTK_SRCS = \
 	hid/gtk/gui-dialog-print.c \
 	hid/gtk/gui-dialog-size.c \
 	hid/gtk/gui-dialog.c \
+	hid/gtk/gui-drc-window.c \
+	hid/gtk/gui-drc-window.h \
 	hid/gtk/gui-keyref-window.c \
 	hid/gtk/gui-library-window.c \
 	hid/gtk/gui-library-window.h \
diff --git a/src/action.c b/src/action.c
index 7b78fed..6e7af6f 100644
--- a/src/action.c
+++ b/src/action.c
@@ -1746,6 +1746,8 @@ ActionDRCheck (int argc, char **argv, int x, int y)
 {
   int count;
 
+  /* TODO: Override some of these messages for a GUI driven DRC ? */
+
   Message (_("Rules are minspace %d.%02d, minoverlap %d.%d "
 	     "minwidth %d.%02d, minsilk %d.%02d\n"
 	     "min drill %d.%02d, min annular ring %d.%02d\n"),
diff --git a/src/find.c b/src/find.c
index 94ace4d..9c584a6 100644
--- a/src/find.c
+++ b/src/find.c
@@ -157,11 +157,62 @@ RCSID ("$Id$");
 #define	IS_PV_ON_PAD(PV,Pad) \
 	( IsPointInPad((PV)->X, (PV)->Y, MAX((PV)->Thickness/2 +Bloat,0), (Pad)))
 
-static char drc_dialog_message[289];
+#define LENGTH_TO_HUMAN(value) (Settings.grid_units_mm ? ((value) / 100000.0 * 25.4) : ((value) / 100.0))
+#define LENGTH_DIGITS (Settings.grid_units_mm ? 4 : 2)
+#define LENGTH_UNITS_STRING (Settings.grid_units_mm ? "mm" : "mils")
+
+
+static DRC_VIOLATION
+*pcb_drc_violation_new (char *title,
+                        char *explanation,
+                        int x, int y,
+                        int angle,
+                        double measured_value,
+                        double required_value,
+                        int value_digits,
+                        const char *value_units,
+                        int object_count,
+                        long int *object_id_list,
+                        int *object_type_list)
+{
+  DRC_VIOLATION *violation = malloc (sizeof (DRC_VIOLATION));
+
+  violation->title = strdup (title);
+  violation->explanation = strdup (explanation);
+  violation->x = x;
+  violation->y = y;
+  violation->angle = angle;
+  violation->measured_value = measured_value;
+  violation->required_value = required_value;
+  violation->value_digits = value_digits;
+  violation->value_units = value_units;
+  violation->object_count = object_count;
+  violation->object_id_list = object_id_list;
+  violation->object_type_list = object_type_list;
+
+  return violation;
+}
+
+static void
+pcb_drc_violation_free (DRC_VIOLATION *violation)
+{
+  free (violation->title);
+  free (violation->explanation);
+  free (violation);
+}
+
+static char drc_dialog_message[289] = {0,};
 static void
 reset_drc_dialog_message(void)
 {
-   drc_dialog_message[0] = 0;
+  if (gui->drc_gui != NULL)
+    {
+      gui->drc_gui->reset_drc_dialog_message ();
+    }
+  else
+    {
+      drc_dialog_message[0] = 0;
+    }
 }
 #ifdef __GNUC__
 static void append_drc_dialog_message(const char *fmt, ...)
@@ -170,18 +221,42 @@ static void append_drc_dialog_message(const char *fmt, ...)
 static void
 append_drc_dialog_message(const char *fmt, ...)
 {
-  size_t len = strlen (drc_dialog_message), 
-         remained = sizeof (drc_dialog_message) - len - 1;
+  size_t len, remained;
   va_list ap;
+
   va_start (ap, fmt);
+
+  if (gui->drc_gui != NULL)
+    {
+      printf ("FUBAR\n");
+      //gui->drc_gui->append_drc_dialog_messagev (fmt, ap);
+    }
+  else
+    {
+      len = strlen (drc_dialog_message);
+      remained = sizeof (drc_dialog_message) - len - 1;
 #ifdef HAVE_VSNPRINTF
-  vsnprintf (drc_dialog_message + len, remained, fmt, ap);
+      vsnprintf (drc_dialog_message + len, remained, fmt, ap);
 #else
-  vsprintf (drc_dialog_message + len, fmt, ap);
+      vsprintf (drc_dialog_message + len, fmt, ap);
 #endif
+    }
+
   va_end (ap);
 }
 
+static void
+append_drc_violation (DRC_VIOLATION *violation)
+{
+  if (gui->drc_gui != NULL)
+    {
+      gui->drc_gui->append_drc_violation (violation);
+    }
+  else
+    {
+      /* FALLBACK TO THE OLD WAY? */
+    }
+}
 /*
  * message when asked about continuing DRC checks after next 
  * violation is found.
@@ -194,9 +269,18 @@ static int
 throw_drc_dialog(void)
 {
   int r;
-  append_drc_dialog_message (DRC_CONTINUE); 
-  r = gui->confirm_dialog (drc_dialog_message, DRC_CANCEL, DRC_NEXT);
-  reset_drc_dialog_message();
+
+  if (gui->drc_gui != NULL)
+    {
+      r = gui->drc_gui->throw_drc_dialog ();
+//      gui->drc_gui->reset_drc_dialog_message ();
+    }
+  else
+    {
+      append_drc_dialog_message (DRC_CONTINUE);
+      r = gui->confirm_dialog (drc_dialog_message, DRC_CANCEL, DRC_NEXT);
+      reset_drc_dialog_message();
+    }
   return r;
 }
 
@@ -261,6 +345,8 @@ static Boolean PrintAndSelectUnusedPinsAndPadsOfElement (ElementTypePtr,
 static void DrawNewConnections (void);
 static void ResetConnections (Boolean);
 static void DumpList (void);
+static void LocateError (LocationType *, LocationType *);
+static void BuildObjectList (int *, long int **, int **);
 static void GotoError (void);
 static Boolean DRCFind (int, void *, void *, void *);
 static Boolean ListStart (int, void *, void *, void *);
@@ -3467,7 +3553,13 @@ DumpList (void)
 static Boolean
 DRCFind (int What, void *ptr1, void *ptr2, void *ptr3)
 {
-  reset_drc_dialog_message();
+  LocationType x, y;
+  int object_count;
+  long int *object_id_list;
+  int *object_type_list;
+  DRC_VIOLATION *violation;
+
+//  reset_drc_dialog_message();
   if (PCB->Shrink != 0)
     {
       Bloat = -PCB->Shrink;
@@ -3488,7 +3580,6 @@ DRCFind (int What, void *ptr1, void *ptr2, void *ptr3)
           Message
             (_
              ("WARNING!!  Design Rule Error - potential for broken trace!\n"));
-          append_drc_dialog_message(_("potential for broken trace\n"));
           /* make the flag changes undoable */
           TheFlag = FOUNDFLAG | SELECTEDFLAG;
           ResetConnections (False);
@@ -3511,7 +3602,25 @@ DRCFind (int What, void *ptr1, void *ptr2, void *ptr3)
           User = False;
           drc = False;
           drcerr_count++;
-          GotoError ();
+          LocateError (&x, &y);
+          BuildObjectList (&object_count, &object_id_list, &object_type_list);
+          violation = pcb_drc_violation_new (_("Potential for broken trace"),
+                                             _("Insufficient overlap between objects can lead to broken tracks\n"
+                                               "due to registration errors with old wheel style photo-plotters."),
+                                             x, y,
+                                             0, /* ANGLE OF ERROR UNKNOWN */
+                                             0, /* MAGNITURE OF ERROR UNKNOWN */
+                                             LENGTH_TO_HUMAN(PCB->Shrink),
+                                             LENGTH_DIGITS,
+                                             LENGTH_UNITS_STRING,
+                                             object_count,
+                                             object_id_list,
+                                             object_type_list);
+          append_drc_violation (violation);
+          pcb_drc_violation_free (violation);
+          free (object_id_list);
+          free (object_type_list);
+
           if (!throw_drc_dialog())
             return (True);
           IncrementUndoSerialNumber ();
@@ -3531,7 +3640,6 @@ DRCFind (int What, void *ptr1, void *ptr2, void *ptr3)
     {
       DumpList ();
       Message (_("WARNING!  Design Rule error - copper areas too close!\n"));
-      append_drc_dialog_message(_("copper areas too close\n"));
       /* make the flag changes undoable */
       TheFlag = FOUNDFLAG | SELECTEDFLAG;
       ResetConnections (False);
@@ -3552,7 +3660,24 @@ DRCFind (int What, void *ptr1, void *ptr2, void *ptr3)
       DoIt (True, True);
       DumpList ();
       drcerr_count++;
-      GotoError ();
+      LocateError (&x, &y);
+      BuildObjectList (&object_count, &object_id_list, &object_type_list);
+      violation = pcb_drc_violation_new (_("Copper areas too close"),
+                                         _("Circuits that are too close may bridge during imaging, etching,\n"
+                                           "plating, or soldering processes resulting in a direct short."),
+                                         x, y,
+                                         0, /* ANGLE OF ERROR UNKNOWN */
+                                         0, /* MAGNITURE OF ERROR UNKNOWN */
+                                         LENGTH_TO_HUMAN(PCB->Bloat),
+                                         LENGTH_DIGITS,
+                                         LENGTH_UNITS_STRING,
+                                         object_count,
+                                         object_id_list,
+                                         object_type_list);
+      append_drc_violation (violation);
+      pcb_drc_violation_free (violation);
+      free (object_id_list);
+      free (object_type_list);
       User = False;
       drc = False;
       if (!throw_drc_dialog())
@@ -3603,6 +3728,13 @@ static int
 drc_callback (DataTypePtr data, LayerTypePtr layer, PolygonTypePtr polygon,
               int type, void *ptr1, void *ptr2)
 {
+  char *message;
+  LocationType x, y;
+  int object_count;
+  long int *object_id_list;
+  int *object_type_list;
+  DRC_VIOLATION *violation;
+
   LineTypePtr line = (LineTypePtr) ptr2;
   ArcTypePtr arc = (ArcTypePtr) ptr2;
   PinTypePtr pin = (PinTypePtr) ptr2;
@@ -3619,9 +3751,8 @@ drc_callback (DataTypePtr data, LayerTypePtr layer, PolygonTypePtr polygon,
         {
           AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
           SET_FLAG (TheFlag, line);
-          Message (_("Line with insufficient clearance inside polygon\n"));
-          append_drc_dialog_message(_("line inside polygon\n"
-            "with insufficient clearance\n"));
+          message = _("Line with insufficient clearance inside polygon\n");
+          Message (message);
           goto doIsBad;
         }
       break;
@@ -3630,9 +3761,8 @@ drc_callback (DataTypePtr data, LayerTypePtr layer, PolygonTypePtr polygon,
         {
           AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
           SET_FLAG (TheFlag, arc);
-          Message (_("Arc with insufficient clearance inside polygon\n"));
-          append_drc_dialog_message(_("arc inside polygon\n"
-            "with insufficient clearance\n"));
+          message = _("Arc with insufficient clearance inside polygon\n");
+          Message (message);
           goto doIsBad;
         }
       break;
@@ -3642,9 +3772,8 @@ drc_callback (DataTypePtr data, LayerTypePtr layer, PolygonTypePtr polygon,
 	  {
 	    AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
 	    SET_FLAG (TheFlag, pad);
-	    Message (_("Pad with insufficient clearance inside polygon\n"));
-	    append_drc_dialog_message(_("pad inside polygon\n"
-          "with insufficient clearance\n"));
+	    message = _("Pad with insufficient clearance inside polygon\n");
+	    Message (message);
 	    goto doIsBad;
 	  }
       break;
@@ -3653,9 +3782,8 @@ drc_callback (DataTypePtr data, LayerTypePtr layer, PolygonTypePtr polygon,
         {
           AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
           SET_FLAG (TheFlag, pin);
-          Message (_("Pin with insufficient clearance inside polygon\n"));
-          append_drc_dialog_message(_("pin inside polygon\n"
-            "with insufficient clearance\n"));
+          message = _("Pin with insufficient clearance inside polygon\n");
+          Message (message);
           goto doIsBad;
         }
       break;
@@ -3664,16 +3792,15 @@ drc_callback (DataTypePtr data, LayerTypePtr layer, PolygonTypePtr polygon,
         {
           AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2);
           SET_FLAG (TheFlag, pin);
-          Message (_("Via with insufficient clearance inside polygon\n"));
-          append_drc_dialog_message(_("via inside polygon\n"
-            "with insufficient clearance\n"));
+          message = _("Via with insufficient clearance inside polygon\n");
+          Message (message);
           goto doIsBad;
         }
       break;
     default:
       Message ("hace: Bad Plow object in callback\n");
-      append_drc_dialog_message(_("wrong object inside polygon\n"
-        "with insufficient clearance\n"));
+//      append_drc_dialog_message(_("wrong object inside polygon\n"
+//        "with insufficient clearance\n"));
     }
   return 0;
 
@@ -3683,7 +3810,24 @@ doIsBad:
   DrawPolygon (layer, polygon, 0);
   DrawObject (type, ptr1, ptr2, 0);
   drcerr_count++;
-  GotoError ();
+  LocateError (&x, &y);
+  BuildObjectList (&object_count, &object_id_list, &object_type_list);
+  violation = pcb_drc_violation_new (message,
+                                     _("Circuits that are too close may bridge during imaging, etching,\n"
+                                       "plating, or soldering processes resulting in a direct short."),
+                                     x, y,
+                                     0, /* ANGLE OF ERROR UNKNOWN */
+                                     0, /* MAGNITURE OF ERROR UNKNOWN */
+                                     LENGTH_TO_HUMAN(PCB->Bloat),
+                                     LENGTH_DIGITS,
+                                     LENGTH_UNITS_STRING,
+                                     object_count,
+                                     object_id_list,
+                                     object_type_list);
+  append_drc_violation (violation);
+  pcb_drc_violation_free (violation);
+  free (object_id_list);
+  free (object_type_list);
   if (!throw_drc_dialog())
     {
       IsBad = True;
@@ -3701,9 +3845,16 @@ doIsBad:
 int
 DRCAll (void)
 {
+  LocationType x, y;
+  int object_count;
+  long int *object_id_list;
+  int *object_type_list;
+  DRC_VIOLATION *violation;
   int tmpcnt;
   int nopastecnt = 0;
 
+  reset_drc_dialog_message();
+
   IsBad = False;
   drcerr_count = 0;
   SaveStackAndVisibility ();
@@ -3779,11 +3930,27 @@ DRCAll (void)
             AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
             SET_FLAG (TheFlag, line);
             Message (_("Line is too thin\n"));
-            append_drc_dialog_message(_("too thin line\n"));
             DrawLine (layer, line, 0);
             drcerr_count++;
             SetThing (LINE_TYPE, layer, line, line);
-            GotoError ();
+            LocateError (&x, &y);
+            BuildObjectList (&object_count, &object_id_list, &object_type_list);
+            violation = pcb_drc_violation_new (_("Line width is too thin"),
+                                               _("Process specifications dictate a minimum feature-width\n"
+                                                 "that can reliably be reproduced"),
+                                               x, y,
+                                               0, /* ANGLE OF ERROR UNKNOWN */
+                                               LENGTH_TO_HUMAN(line->Thickness),
+                                               LENGTH_TO_HUMAN(PCB->minWid),
+                                               LENGTH_DIGITS,
+                                               LENGTH_UNITS_STRING,
+                                               object_count,
+                                               object_id_list,
+                                               object_type_list);
+            append_drc_violation (violation);
+            pcb_drc_violation_free (violation);
+            free (object_id_list);
+            free (object_type_list);
             if (!throw_drc_dialog())
               {
                 IsBad = True;
@@ -3807,11 +3974,27 @@ DRCAll (void)
             AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
             SET_FLAG (TheFlag, arc);
             Message (_("Arc is too thin\n"));
-            append_drc_dialog_message(_("too thin arc\n"));
             DrawArc (layer, arc, 0);
             drcerr_count++;
             SetThing (ARC_TYPE, layer, arc, arc);
-            GotoError ();
+            LocateError (&x, &y);
+            BuildObjectList (&object_count, &object_id_list, &object_type_list);
+            violation = pcb_drc_violation_new (_("Arc width is too thin"),
+                                               _("Process specifications dictate a minimum feature-width\n"
+                                                 "that can reliably be reproduced"),
+                                               x, y,
+                                               0, /* ANGLE OF ERROR UNKNOWN */
+                                               LENGTH_TO_HUMAN(arc->Thickness),
+                                               LENGTH_TO_HUMAN(PCB->minWid),
+                                               LENGTH_DIGITS,
+                                               LENGTH_UNITS_STRING,
+                                               object_count,
+                                               object_id_list,
+                                               object_type_list);
+            append_drc_violation (violation);
+            pcb_drc_violation_free (violation);
+            free (object_id_list);
+            free (object_type_list);
             if (!throw_drc_dialog())
               {
                 IsBad = True;
@@ -3837,11 +4020,27 @@ DRCAll (void)
             SET_FLAG (TheFlag, pin);
             Message (_
                      ("Pin annular ring is too small based on minimum annular ring\n"));
-            append_drc_dialog_message(_("pin ring thinner\nthan min annular ring\n"));
             DrawPin (pin, 0);
             drcerr_count++;
             SetThing (PIN_TYPE, element, pin, pin);
-            GotoError ();
+            LocateError (&x, &y);
+            BuildObjectList (&object_count, &object_id_list, &object_type_list);
+            violation = pcb_drc_violation_new (_("Pin annular ring too small"),
+                                               _("Annular rings that are too small may erode during etching,\n"
+                                                 "resulting in a broken connection"),
+                                               x, y,
+                                               0, /* ANGLE OF ERROR UNKNOWN */
+                                               LENGTH_TO_HUMAN((pin->Thickness - pin->DrillingHole) / 2),
+                                               LENGTH_TO_HUMAN(PCB->minRing),
+                                               LENGTH_DIGITS,
+                                               LENGTH_UNITS_STRING,
+                                               object_count,
+                                               object_id_list,
+                                               object_type_list);
+            append_drc_violation (violation);
+            pcb_drc_violation_free (violation);
+            free (object_id_list);
+            free (object_type_list);
             if (!throw_drc_dialog())
               {
                 IsBad = True;
@@ -3855,11 +4054,26 @@ DRCAll (void)
             AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
             SET_FLAG (TheFlag, pin);
             Message (_("Pin drill size is too small\n"));
-            append_drc_dialog_message(_("too small pin drill\n"));
             DrawPin (pin, 0);
             drcerr_count++;
             SetThing (PIN_TYPE, element, pin, pin);
-            GotoError ();
+            LocateError (&x, &y);
+            BuildObjectList (&object_count, &object_id_list, &object_type_list);
+            violation = pcb_drc_violation_new (_("Pin drill size is too small"),
+                                               _("Process rules dictate the minimum drill size which can be used"),
+                                               x, y,
+                                               0, /* ANGLE OF ERROR UNKNOWN */
+                                               LENGTH_TO_HUMAN(pin->DrillingHole),
+                                               LENGTH_TO_HUMAN(PCB->minDrill),
+                                               LENGTH_DIGITS,
+                                               LENGTH_UNITS_STRING,
+                                               object_count,
+                                               object_id_list,
+                                               object_type_list);
+            append_drc_violation (violation);
+            pcb_drc_violation_free (violation);
+            free (object_id_list);
+            free (object_type_list);
             if (!throw_drc_dialog())
               {
                 IsBad = True;
@@ -3883,11 +4097,27 @@ DRCAll (void)
             AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
             SET_FLAG (TheFlag, pad);
             Message (_("Pad is too thin\n"));
-            append_drc_dialog_message(_("too thin pad\n"));
             DrawPad (pad, 0);
             drcerr_count++;
             SetThing (PAD_TYPE, element, pad, pad);
-            GotoError ();
+            LocateError (&x, &y);
+            BuildObjectList (&object_count, &object_id_list, &object_type_list);
+            violation = pcb_drc_violation_new (_("Pad is too thin"),
+                                               _("Pads which are too thin may erode during etching,\n"
+                                                  "resulting in a broken or unreliable connection"),
+                                               x, y,
+                                               0, /* ANGLE OF ERROR UNKNOWN */
+                                               LENGTH_TO_HUMAN(pad->Thickness),
+                                               LENGTH_TO_HUMAN(PCB->minWid),
+                                               LENGTH_DIGITS,
+                                               LENGTH_UNITS_STRING,
+                                               object_count,
+                                               object_id_list,
+                                               object_type_list);
+            append_drc_violation (violation);
+            pcb_drc_violation_free (violation);
+            free (object_id_list);
+            free (object_type_list);
             if (!throw_drc_dialog())
               {
                 IsBad = True;
@@ -3913,11 +4143,27 @@ DRCAll (void)
             SET_FLAG (TheFlag, via);
             Message (_
                      ("Via annular ring is too small based on minimum annular ring\n"));
-            append_drc_dialog_message(_("via ring thinner\nthan min annular ring\n"));
             DrawVia (via, 0);
             drcerr_count++;
             SetThing (VIA_TYPE, via, via, via);
-            GotoError ();
+            LocateError (&x, &y);
+            BuildObjectList (&object_count, &object_id_list, &object_type_list);
+            violation = pcb_drc_violation_new (_("Via annular ring too small"),
+                                               _("Annular rings that are too small may erode during etching,\n"
+                                                 "resulting in a broken connection"),
+                                               x, y,
+                                               0, /* ANGLE OF ERROR UNKNOWN */
+                                               LENGTH_TO_HUMAN((via->Thickness - via->DrillingHole) / 2),
+                                               LENGTH_TO_HUMAN(PCB->minRing),
+                                               LENGTH_DIGITS,
+                                               LENGTH_UNITS_STRING,
+                                               object_count,
+                                               object_id_list,
+                                               object_type_list);
+            append_drc_violation (violation);
+            pcb_drc_violation_free (violation);
+            free (object_id_list);
+            free (object_type_list);
             if (!throw_drc_dialog())
               {
                 IsBad = True;
@@ -3931,11 +4177,26 @@ DRCAll (void)
             AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
             SET_FLAG (TheFlag, via);
             Message (_("Via drill size is too small\n"));
-            append_drc_dialog_message(_("too small via drill\n"));
             DrawVia (via, 0);
             drcerr_count++;
             SetThing (VIA_TYPE, via, via, via);
-            GotoError ();
+            LocateError (&x, &y);
+            BuildObjectList (&object_count, &object_id_list, &object_type_list);
+            violation = pcb_drc_violation_new (_("Via drill size is too small"),
+                                               _("Process rules dictate the minimum drill size which can be used"),
+                                               x, y,
+                                               0, /* ANGLE OF ERROR UNKNOWN */
+                                               LENGTH_TO_HUMAN(via->DrillingHole),
+                                               LENGTH_TO_HUMAN(PCB->minDrill),
+                                               LENGTH_DIGITS,
+                                               LENGTH_UNITS_STRING,
+                                               object_count,
+                                               object_id_list,
+                                               object_type_list);
+            append_drc_violation (violation);
+            pcb_drc_violation_free (violation);
+            free (object_id_list);
+            free (object_type_list);
             if (!throw_drc_dialog())
               {
                 IsBad = True;
@@ -3964,11 +4225,27 @@ DRCAll (void)
           {
             SET_FLAG (TheFlag, line);
             Message (_("Silk line is too thin\n"));
-            append_drc_dialog_message(_("too thin silk line\n"));
             DrawLine (layer, line, 0);
             drcerr_count++;
             SetThing (LINE_TYPE, layer, line, line);
-            GotoError ();
+            LocateError (&x, &y);
+            BuildObjectList (&object_count, &object_id_list, &object_type_list);
+            violation = pcb_drc_violation_new (_("Silk line is too thin"),
+                                               _("Process specifications dictate a minimum silkscreen feature-width\n"
+                                                 "that can reliably be reproduced"),
+                                               x, y,
+                                               0, /* ANGLE OF ERROR UNKNOWN */
+                                               LENGTH_TO_HUMAN(line->Thickness),
+                                               LENGTH_TO_HUMAN(PCB->minSlk),
+                                               LENGTH_DIGITS,
+                                               LENGTH_UNITS_STRING,
+                                               object_count,
+                                               object_id_list,
+                                               object_type_list);
+            append_drc_violation (violation);
+            pcb_drc_violation_free (violation);
+            free (object_id_list);
+            free (object_type_list);
             if (!throw_drc_dialog())
               {
                 IsBad = True;
@@ -3998,13 +4275,30 @@ DRCAll (void)
             SET_FLAG (TheFlag, element);
             Message (_("Element %s has %d silk lines which are too thin\n"),
                      UNKNOWN (NAMEONPCB_NAME (element)), tmpcnt);
-            append_drc_dialog_message (_
-                     ("%i silk lines\n of element %s\nare too thin\n"),
-                     tmpcnt, UNKNOWN (NAMEONPCB_NAME (element)));
+//            append_drc_dialog_message (_
+//                     ("%i silk lines\n of element %s\nare too thin\n"),
+//                     tmpcnt, UNKNOWN (NAMEONPCB_NAME (element)));
             DrawElement (element, 0);
             drcerr_count++;
             SetThing (ELEMENT_TYPE, element, element, element);
-            GotoError ();
+            LocateError (&x, &y);
+            BuildObjectList (&object_count, &object_id_list, &object_type_list);
+            violation = pcb_drc_violation_new (_("Element {FIXME} has {FIXME} silk lines which are too thin"),
+                                               _("Process specifications dictate a minimum silkscreen feature-width\n"
+                                                 "that can reliably be reproduced"),
+                                               x, y,
+                                               0, /* ANGLE OF ERROR UNKNOWN */
+                                               0, /* MINIMUM OFFENDING WIDTH UNKNOWN */
+                                               LENGTH_TO_HUMAN(PCB->minSlk),
+                                               LENGTH_DIGITS,
+                                               LENGTH_UNITS_STRING,
+                                               object_count,
+                                               object_id_list,
+                                               object_type_list);
+            append_drc_violation (violation);
+            pcb_drc_violation_free (violation);
+            free (object_id_list);
+            free (object_type_list);
             if (!throw_drc_dialog())
               {
                 IsBad = True;
@@ -4036,36 +4330,34 @@ DRCAll (void)
 }
 
 /*----------------------------------------------------------------------------
- * center the display to show the offending item (thing)
+ * Locate the coordinatates of offending item (thing)
  */
 static void
-GotoError (void)
+LocateError (LocationType *x, LocationType *y)
 {
-  LocationType X, Y;
-
   switch (thing_type)
     {
     case LINE_TYPE:
       {
         LineTypePtr line = (LineTypePtr) thing_ptr3;
-        X = (line->Point1.X + line->Point2.X) / 2;
-        Y = (line->Point1.Y + line->Point2.Y) / 2;
+        *x = (line->Point1.X + line->Point2.X) / 2;
+        *y = (line->Point1.Y + line->Point2.Y) / 2;
         break;
       }
     case ARC_TYPE:
       {
         ArcTypePtr arc = (ArcTypePtr) thing_ptr3;
-        X = arc->X;
-        Y = arc->Y;
+        *x = arc->X;
+        *y = arc->Y;
         break;
       }
     case POLYGON_TYPE:
       {
         PolygonTypePtr polygon = (PolygonTypePtr) thing_ptr3;
-        X =
+        *x =
           (polygon->Clipped->contours->xmin +
            polygon->Clipped->contours->xmax) / 2;
-        Y =
+        *y =
           (polygon->Clipped->contours->ymin +
            polygon->Clipped->contours->ymax) / 2;
         break;
@@ -4074,33 +4366,75 @@ GotoError (void)
     case VIA_TYPE:
       {
         PinTypePtr pin = (PinTypePtr) thing_ptr3;
-        X = pin->X;
-        Y = pin->Y;
+        *x = pin->X;
+        *y = pin->Y;
         break;
       }
     case PAD_TYPE:
       {
         PadTypePtr pad = (PadTypePtr) thing_ptr3;
-        X = (pad->Point1.X + pad->Point2.X) / 2;
-        Y = (pad->Point1.Y + pad->Point2.Y) / 2;
+        *x = (pad->Point1.X + pad->Point2.X) / 2;
+        *y = (pad->Point1.Y + pad->Point2.Y) / 2;
         break;
       }
     case ELEMENT_TYPE:
       {
         ElementTypePtr element = (ElementTypePtr) thing_ptr3;
-        X = element->MarkX;
-        Y = element->MarkY;
+        *x = element->MarkX;
+        *y = element->MarkY;
         break;
       }
     default:
       return;
     }
+}
+
+
+/*----------------------------------------------------------------------------
+ * Build a list of the of offending items by ID. (Currently just "thing")
+ */
+static void
+BuildObjectList (int *object_count, long int **object_id_list, int **object_type_list)
+{
+  *object_count = 0;
+  *object_id_list = NULL;
+
+  switch (thing_type)
+    {
+    case LINE_TYPE:
+    case ARC_TYPE:
+    case POLYGON_TYPE:
+    case PIN_TYPE:
+    case VIA_TYPE:
+    case PAD_TYPE:
+    case ELEMENT_TYPE:
+      *object_count = 1;
+      *object_id_list = malloc (sizeof (long int));
+      *object_type_list = malloc (sizeof (int));
+      **object_id_list = ((AnyObjectType *)thing_ptr3)->ID;
+      **object_type_list = thing_type;
+      return;
+
+    default:
+      return;
+    }
+}
+
+
+/*----------------------------------------------------------------------------
+ * center the display to show the offending item (thing)
+ */
+static void
+GotoError (void)
+{
+  LocationType X, Y;
+
+  LocateError (&X, &Y);
+
   {
-    int digits = Settings.grid_units_mm ? 4: 2;
     double scale = Settings.grid_units_mm ? COOR_TO_MM : 1./100,
       x = X * scale, y = Y * scale;
-    Message (_("near location (%.*f,%.*f)\n"), digits, x, digits, y);
-    append_drc_dialog_message("near (%.*f,%.*f)\n", digits, x, digits, y);
+    Message (_("near location (%.*f,%.*f)\n"), LENGTH_DIGITS, x, LENGTH_DIGITS, y);
   }
   switch (thing_type)
     {
diff --git a/src/gpcb-menu.res b/src/gpcb-menu.res
index 5e56536..26e15e8 100644
--- a/src/gpcb-menu.res
+++ b/src/gpcb-menu.res
@@ -445,6 +445,7 @@ MainMenu =
   {Window
    {"Library" DoWindows(Library) a={"i" "<Key>i"}}
    {"Message Log" DoWindows(Log)}
+   {"DRC Check" DoWindows(DRC)}
    {"Netlist" DoWindows(Netlist)}
    {"Command Entry" Command() a={":" "<Key>:"}}
    {"Pinout" Display(Pinout) a={"Shift-D" "Shift<Key>d"}}
diff --git a/src/hid.h b/src/hid.h
index 6cceaaf..a8b256a 100644
--- a/src/hid.h
+++ b/src/hid.h
@@ -229,6 +229,31 @@ typedef enum
   PCB_WATCH_HANGUP   = 1 << 3  /**< As in POLLHUP */
 } PCBWatchFlags;
 
+typedef struct
+{
+  char *title;
+  char *explanation;
+  int x;
+  int y;
+  int angle;
+  double measured_value;
+  double required_value;
+  int value_digits;
+  const char *value_units;
+  int object_count;
+  long int *object_id_list;
+  int *object_type_list;
+} DRC_VIOLATION;
+
+/* DRC GUI Hooks */
+  typedef struct
+  {
+    void (*reset_drc_dialog_message) (void);
+    void (*append_drc_violation) (DRC_VIOLATION *violation);
+//    void (*append_drc_dialog_messagev) (const char *fmt, va_list va);
+    int (*throw_drc_dialog) (void);
+  } HID_DRC_GUI;
+
 
 /* This is the main HID structure.  */
   typedef struct
@@ -536,6 +561,8 @@ typedef enum
        Returns nonzero if the user wishes to cancel the operation.  */
     int (*progress) (int so_far_, int total_, const char *message_);
 
+    HID_DRC_GUI *drc_gui;
+
   } HID;
 
 /* Call this as soon as possible from main().  No other HID calls are
diff --git a/src/hid/batch/batch.c b/src/hid/batch/batch.c
index 3e80139..5479b46 100644
--- a/src/hid/batch/batch.c
+++ b/src/hid/batch/batch.c
@@ -507,7 +507,8 @@ HID batch_gui = {
   batch_attribute_dialog,
   batch_show_item,
   batch_beep,
-  batch_progress
+  batch_progress,
+  0 /* batch_drc_gui */
 };
 
 #include "dolists.h"
diff --git a/src/hid/bom/bom.c b/src/hid/bom/bom.c
index 18fca46..9892269 100644
--- a/src/hid/bom/bom.c
+++ b/src/hid/bom/bom.c
@@ -587,6 +587,7 @@ HID bom_hid = {
   0,				/* bom_show_item */
   0,				/* bom_beep */
   0,				/* bom_progress */
+  0,				/* bom_drc_gui */
 };
 
 void
diff --git a/src/hid/common/hidnogui.c b/src/hid/common/hidnogui.c
index 57509dc..5c33332 100644
--- a/src/hid/common/hidnogui.c
+++ b/src/hid/common/hidnogui.c
@@ -394,7 +394,8 @@ HID hid_nogui = {
   nogui_attribute_dialog,
   nogui_show_item,
   nogui_beep,
-  nogui_progress
+  nogui_progress,
+  0 /* nogui_drc_gui */
 };
 
 #define AD(x) if (!d->x) d->x = s->x
@@ -447,4 +448,5 @@ apply_default_hid (HID * d, HID * s)
   AD (show_item);
   AD (beep);
   AD (progress);
+  AD (drc_gui);
 }
diff --git a/src/hid/gerber/gerber.c b/src/hid/gerber/gerber.c
index 0f70e2a..29f69bf 100644
--- a/src/hid/gerber/gerber.c
+++ b/src/hid/gerber/gerber.c
@@ -1129,7 +1129,9 @@ static HID gerber_hid = {
   0 /* gerber_fileselect */ ,
   0 /* gerber_attribute_dialog */ ,
   0 /* gerber_show_item */ ,
-  0				/* gerber_beep */
+  0 /* gerber_beep */ ,
+  0 /* gerber_progress */ ,
+  0 /* gerber_drc_gui */
 };
 
 void
diff --git a/src/hid/gtk/gtkhid-main.c b/src/hid/gtk/gtkhid-main.c
index ad11ba8..4653335 100644
--- a/src/hid/gtk/gtkhid-main.c
+++ b/src/hid/gtk/gtkhid-main.c
@@ -1474,6 +1474,12 @@ ghid_progress (int so_far, int total, const char *message)
 }
 
 /* ---------------------------------------------------------------------- */
+HID_DRC_GUI ghid_drc_gui = {
+  ghid_drc_window_reset_message,
+  ghid_drc_window_append_violation,
+//  ghid_drc_window_append_messagev,
+  ghid_drc_window_throw_dialog
+};
 
 HID ghid_hid = {
   sizeof (HID),
@@ -1534,7 +1540,8 @@ HID ghid_hid = {
   ghid_attribute_dialog,
   ghid_show_item,
   ghid_beep,
-  ghid_progress
+  ghid_progress,
+  &ghid_drc_gui
 };
 
 HID ghid_extents = {
@@ -1595,7 +1602,8 @@ HID ghid_extents = {
   0 /* ghid_attribute_dialog */ ,
   0 /* ghid_show_item */ ,
   0 /* ghid_beep */ ,
-  0 /* ghid_progress */
+  0 /* ghid_progress */ ,
+  0 /* ghid_drc_gui */
 };
 
 /* ------------------------------------------------------------ 
@@ -2340,8 +2348,8 @@ CursorAction(int argc, char **argv, int x, int y)
 /* ------------------------------------------------------------ */
 
 static const char dowindows_syntax[] =
-"DoWindows(1|2|3|4)\n"
-"DoWindows(Layout|Library|Log|Netlist|Preferences)";
+"DoWindows(1|2|3|4|5|6)\n"
+"DoWindows(Layout|Library|Log|Netlist|Preferences|DRC)";
 
 static const char dowindows_help[] =
 "Open various GUI windows.";
@@ -2371,6 +2379,10 @@ Open the netlist window.
 @itemx Preferences
 Open the preferences window.
 
+@item 6
+@itemx DRC
+Open the DRC violations window.
+
 @end table
 
 %end-doc */
@@ -2399,6 +2411,10 @@ DoWindows (int argc, char **argv, int x, int y)
     {
       ghid_config_window_show ();
     }
+  else if (strcmp (a, "6") == 0 || strcasecmp (a, "DRC") == 0)
+    {
+      ghid_drc_window_show (TRUE);
+    }
   else
     {
       AFAIL (dowindows);
diff --git a/src/hid/gtk/gui-config.c b/src/hid/gtk/gui-config.c
index 1b50d32..23c3164 100644
--- a/src/hid/gtk/gui-config.c
+++ b/src/hid/gtk/gui-config.c
@@ -130,6 +130,8 @@ static ConfigAttribute config_attributes[] = {
   {"top-window-height", CONFIG_Integer, &_ghidgui.top_window_height},
   {"log-window-width", CONFIG_Integer, &_ghidgui.log_window_width},
   {"log-window-height", CONFIG_Integer, &_ghidgui.log_window_height},
+  {"drc-window-width", CONFIG_Integer, &_ghidgui.drc_window_width},
+  {"drc-window-height", CONFIG_Integer, &_ghidgui.drc_window_height},
   {"library-window-width", CONFIG_Integer, &_ghidgui.library_window_width},
   {"library-window-height", CONFIG_Integer, &_ghidgui.library_window_height},
   {"netlist-window-height", CONFIG_Integer, &_ghidgui.netlist_window_height},
diff --git a/src/hid/gtk/gui-drc-window.c b/src/hid/gtk/gui-drc-window.c
new file mode 100644
index 0000000..7632994
--- /dev/null
+++ b/src/hid/gtk/gui-drc-window.c
@@ -0,0 +1,732 @@
+/* $Id$ */
+
+/*
+ *                            COPYRIGHT
+ *
+ *  PCB, interactive printed circuit board design
+ *  Copyright (C) 1994,1995,1996 Thomas Nau
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Contact addresses for paper mail and Email:
+ *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *  Thomas.Nau@xxxxxxxxxxxxx
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "error.h"
+#include "search.h"
+#include "draw.h"
+#include "undo.h"
+#include "gui.h"
+#include "gui-drc-window.h"
+
+#ifdef HAVE_LIBDMALLOC
+#include <dmalloc.h>
+#endif
+
+RCSID ("$Id$");
+
+static GtkWidget *drc_window, *drc_list;
+static GtkListStore *drc_list_model = NULL;
+static int num_violations = 0;
+
+/* Remember user window resizes. */
+static gint
+drc_window_configure_event_cb (GtkWidget * widget,
+			       GdkEventConfigure * ev, gpointer data)
+{
+  ghidgui->drc_window_width = widget->allocation.width;
+  ghidgui->drc_window_height = widget->allocation.height;
+  ghidgui->config_modified = TRUE;
+
+  return FALSE;
+}
+
+static void
+drc_close_cb (gpointer data)
+{
+  gtk_widget_destroy (drc_window);
+  drc_window = NULL;
+}
+
+static void
+drc_destroy_cb (GtkWidget * widget, gpointer data)
+{
+  drc_window = NULL;
+}
+
+enum {
+  DRC_VIOLATION_NUM_COL = 0,
+  DRC_TITLE_COL,
+  DRC_EXPLANATION_COL,
+  DRC_X_COORD_COL,
+  DRC_Y_COORD_COL,
+  DRC_ANGLE_COL,
+  DRC_MEASURED_VALUE_COL,
+  DRC_REQUIRED_VALUE_COL,
+  DRC_VALUE_DIGITS_COL,
+  DRC_VALUE_UNITS_COL,
+  DRC_OBJECT_COUNT_COL,
+  DRC_OBJECT_ID_LIST_COL,
+  DRC_OBJECT_TYPE_LIST_COL,
+  NUM_DRC_COLUMNS
+};
+
+
+#warning NASTY, DOESNT USE UNDO PROPERLY
+static void
+unset_found_flags (int AndDraw)
+{
+  int flag = FOUNDFLAG;
+  int change = 0;
+
+  VIA_LOOP (PCB->Data);
+  {
+    if (TEST_FLAG (flag, via))
+      {
+        if (AndDraw)
+          AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
+        CLEAR_FLAG (flag, via);
+        if (AndDraw)
+          DrawVia (via, 0);
+        change = True;
+      }
+  }
+  END_LOOP;
+  ELEMENT_LOOP (PCB->Data);
+  {
+    PIN_LOOP (element);
+    {
+      if (TEST_FLAG (flag, pin))
+        {
+          if (AndDraw)
+            AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
+          CLEAR_FLAG (flag, pin);
+          if (AndDraw)
+            DrawPin (pin, 0);
+          change = True;
+        }
+    }
+    END_LOOP;
+    PAD_LOOP (element);
+    {
+      if (TEST_FLAG (flag, pad))
+        {
+          if (AndDraw)
+            AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
+          CLEAR_FLAG (flag, pad);
+          if (AndDraw)
+            DrawPad (pad, 0);
+          change = True;
+        }
+    }
+    END_LOOP;
+  }
+  END_LOOP;
+  RAT_LOOP (PCB->Data);
+  {
+    if (TEST_FLAG (flag, line))
+      {
+        if (AndDraw)
+          AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
+        CLEAR_FLAG (flag, line);
+        if (AndDraw)
+          DrawRat (line, 0);
+        change = True;
+      }
+  }
+  END_LOOP;
+  COPPERLINE_LOOP (PCB->Data);
+  {
+    if (TEST_FLAG (flag, line))
+      {
+        if (AndDraw)
+          AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
+        CLEAR_FLAG (flag, line);
+        if (AndDraw)
+          DrawLine (layer, line, 0);
+        change = True;
+      }
+  }
+  ENDALL_LOOP;
+  COPPERARC_LOOP (PCB->Data);
+  {
+    if (TEST_FLAG (flag, arc))
+      {
+        if (AndDraw)
+          AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
+        CLEAR_FLAG (flag, arc);
+        if (AndDraw)
+          DrawArc (layer, arc, 0);
+        change = True;
+      }
+  }
+  ENDALL_LOOP;
+  COPPERPOLYGON_LOOP (PCB->Data);
+  {
+    if (TEST_FLAG (flag, polygon))
+      {
+        if (AndDraw)
+          AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
+        CLEAR_FLAG (flag, polygon);
+        if (AndDraw)
+          DrawPolygon (layer, polygon, 0);
+        change = True;
+      }
+  }
+  ENDALL_LOOP;
+  if (change)
+    {
+      SetChangedFlag (True);
+      if (AndDraw)
+        {
+          IncrementUndoSerialNumber ();
+          Draw ();
+        }
+    }
+}
+
+static void
+selection_changed_cb (GtkTreeSelection *selection, gpointer user_data)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  int object_count;
+#if 0
+  long int *object_id_list;
+  int *object_type_list;
+#else
+  long int object_id;
+  int object_type;
+#endif
+  int i;
+  int x_coord, y_coord;
+
+#warning CHEATING HERE!
+  /* I happen to know I'm only putting 0 or 1 items in the lists of objects.
+     To do this properly requires some memory allocation and tracking to
+     avoid leaks! */
+
+  /* Check there is anything selected, if not; return */
+  if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+    {
+      /* Unflag objects */
+      unset_found_flags (True);
+      return;
+    }
+
+  /* Check the selected node has children, if so; return. */
+  if (gtk_tree_model_iter_has_child (model, &iter))
+    return;
+
+  gtk_tree_model_get (model, &iter,
+                      DRC_X_COORD_COL,          &x_coord,
+                      DRC_Y_COORD_COL,          &y_coord,
+                      DRC_OBJECT_COUNT_COL,     &object_count,
+#if 0
+                      DRC_OBJECT_ID_LIST_COL,   &object_id_list,
+                      DRC_OBJECT_TYPE_LIST_COL, &object_type_list,
+#else
+                      DRC_OBJECT_ID_LIST_COL,   &object_id,
+                      DRC_OBJECT_TYPE_LIST_COL, &object_type,
+#endif
+                      -1);
+
+  unset_found_flags (False);
+
+  /* Flag the objects listed against this DRC violation */
+  for (i = 0; i < object_count; i++)
+    {
+      int found_type;
+      void *ptr1, *ptr2, *ptr3;
+
+      found_type = SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3,
+                                     object_id, object_type);
+      if (found_type == NO_TYPE)
+        {
+          Message (_("Object ID %i identified during DRC was not found. Stale DRC window?\n"),
+                   object_id);
+          continue;
+        }
+      SET_FLAG (FOUNDFLAG, (AnyObjectType *)ptr2);
+      switch (object_type)
+        {
+        case LINE_TYPE:
+        case ARC_TYPE:
+        case POLYGON_TYPE:
+          ChangeGroupVisibility (GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1), True, True);
+        }
+      DrawObject (object_type, ptr1, ptr2, 0);
+    }
+  Draw();
+  CenterDisplay (x_coord, y_coord, False);
+}
+
+
+enum
+{
+  PROP_TITLE = 1,
+  PROP_EXPLANATION,
+  PROP_X_COORD,
+  PROP_Y_COORD,
+  PROP_ANGLE,
+  PROP_MEASURED_VALUE,
+  PROP_REQUIRED_VALUE,
+  PROP_VALUE_DIGITS,
+  PROP_VALUE_UNITS
+};
+
+
+static GObjectClass *ghid_violation_renderer_parent_class = NULL;
+
+
+/*! \brief GObject finalise handler
+ *
+ *  \par Function Description
+ *  Just before the GhidViolationRenderer GObject is finalized, free our
+ *  allocated data, and then chain up to the parent's finalize handler.
+ *
+ *  \param [in] widget  The GObject being finalized.
+ */
+static void
+ghid_violation_renderer_finalize (GObject * object)
+{
+  GhidViolationRenderer *renderer = GHID_VIOLATION_RENDERER (object);
+
+  g_free (renderer->title);
+  g_free (renderer->explanation);
+  g_free (renderer->value_units);
+
+  G_OBJECT_CLASS (ghid_violation_renderer_parent_class)->finalize (object);
+}
+
+
+/*! \brief GObject property setter function
+ *
+ *  \par Function Description
+ *  Setter function for GhidViolationRenderer's GObject properties,
+ *  "settings-name" and "toplevel".
+ *
+ *  \param [in]  object       The GObject whose properties we are setting
+ *  \param [in]  property_id  The numeric id. under which the property was
+ *                            registered with g_object_class_install_property()
+ *  \param [in]  value        The GValue the property is being set from
+ *  \param [in]  pspec        A GParamSpec describing the property being set
+ */
+static void
+ghid_violation_renderer_set_property (GObject * object, guint property_id,
+				  const GValue * value, GParamSpec * pspec)
+{
+  GhidViolationRenderer *renderer = GHID_VIOLATION_RENDERER (object);
+  char *markup;
+
+  switch (property_id)
+    {
+    case PROP_TITLE:
+      g_free (renderer->title);
+      renderer->title = g_value_dup_string (value);
+      break;
+    case PROP_EXPLANATION:
+      g_free (renderer->explanation);
+      renderer->explanation = g_value_dup_string (value);
+      break;
+    case PROP_X_COORD:
+      renderer->x_coord = g_value_get_int (value);
+      break;
+    case PROP_Y_COORD:
+      renderer->y_coord = g_value_get_int (value);
+      break;
+    case PROP_ANGLE:
+      renderer->angle = g_value_get_int (value);
+      break;
+    case PROP_MEASURED_VALUE:
+      renderer->measured_value = g_value_get_double (value);
+      break;
+    case PROP_REQUIRED_VALUE:
+      renderer->required_value = g_value_get_double (value);
+      break;
+    case PROP_VALUE_DIGITS:
+      renderer->value_digits = g_value_get_int (value);
+      break;
+    case PROP_VALUE_UNITS:
+      g_free (renderer->value_units);
+      renderer->value_units = g_value_dup_string (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      return;
+    }
+
+  markup = g_strdup_printf ("<b>%s (%.*f %s)</b>\n"
+                            "<span font_size='1024'> </span>\n"
+                            "<small>"
+                              "<i>%s</i>\n"
+                              "<span font_size='6144'> </span>\n"
+                              "Required: %.*f %s"
+                            "</small>",
+                            renderer->title,
+                            renderer->value_digits,
+                            renderer->measured_value,
+                            renderer->value_units,
+
+                            renderer->explanation,
+
+                            renderer->value_digits,
+                            renderer->required_value,
+                            renderer->value_units);
+
+  g_object_set (object, "markup", markup, NULL);
+  g_free (markup);
+}
+
+
+/*! \brief GObject property getter function
+ *
+ *  \par Function Description
+ *  Getter function for GhidViolationRenderer's GObject properties,
+ *  "settings-name" and "toplevel".
+ *
+ *  \param [in]  object       The GObject whose properties we are getting
+ *  \param [in]  property_id  The numeric id. under which the property was
+ *                            registered with g_object_class_install_property()
+ *  \param [out] value        The GValue in which to return the value of the property
+ *  \param [in]  pspec        A GParamSpec describing the property being got
+ */
+static void
+ghid_violation_renderer_get_property (GObject * object, guint property_id,
+				  GValue * value, GParamSpec * pspec)
+{
+  switch (property_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+
+}
+
+
+/*! \brief GType class initialiser for GhidViolationRenderer
+ *
+ *  \par Function Description
+ *  GType class initialiser for GhidViolationRenderer. We override our parent
+ *  virtual class methods as needed and register our GObject properties.
+ *
+ *  \param [in]  klass       The GhidViolationRendererClass we are initialising
+ */
+static void
+ghid_violation_renderer_class_init (GhidViolationRendererClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = ghid_violation_renderer_finalize;
+  gobject_class->set_property = ghid_violation_renderer_set_property;
+  gobject_class->get_property = ghid_violation_renderer_get_property;
+
+  ghid_violation_renderer_parent_class = g_type_class_peek_parent (klass);
+
+  g_object_class_install_property (gobject_class, PROP_TITLE,
+				   g_param_spec_string ("title",
+							"",
+							"",
+							"",
+							G_PARAM_WRITABLE));
+  g_object_class_install_property (gobject_class, PROP_EXPLANATION,
+				   g_param_spec_string ("explanation",
+							"",
+							"",
+							"",
+							G_PARAM_WRITABLE));
+  g_object_class_install_property (gobject_class, PROP_X_COORD,
+				   g_param_spec_int ("x-coord",
+						     "",
+						     "",
+						     G_MININT,
+						     G_MAXINT,
+						     0,
+						     G_PARAM_WRITABLE));
+  g_object_class_install_property (gobject_class, PROP_Y_COORD,
+				   g_param_spec_int ("y-coord",
+						     "",
+						     "",
+						     G_MININT,
+						     G_MAXINT,
+						     0,
+						     G_PARAM_WRITABLE));
+  g_object_class_install_property (gobject_class, PROP_ANGLE,
+				   g_param_spec_int ("angle",
+						     "",
+						     "",
+						     G_MININT,
+						     G_MAXINT,
+						     0,
+						     G_PARAM_WRITABLE));
+  g_object_class_install_property (gobject_class, PROP_MEASURED_VALUE,
+				   g_param_spec_double ("measured-value",
+						     "",
+						     "",
+						     -G_MAXDOUBLE,
+						     G_MAXDOUBLE,
+						     0.,
+						     G_PARAM_WRITABLE));
+  g_object_class_install_property (gobject_class, PROP_REQUIRED_VALUE,
+				   g_param_spec_double ("required-value",
+						     "",
+						     "",
+						     -G_MINDOUBLE,
+						     G_MAXDOUBLE,
+						     0.,
+						     G_PARAM_WRITABLE));
+  g_object_class_install_property (gobject_class, PROP_VALUE_DIGITS,
+				   g_param_spec_int ("value-digits",
+						     "",
+						     "",
+						     0,
+						     G_MAXINT,
+						     0,
+						     G_PARAM_WRITABLE));
+  g_object_class_install_property (gobject_class, PROP_VALUE_UNITS,
+				   g_param_spec_string ("value-units",
+							"",
+							"",
+							"",
+							G_PARAM_WRITABLE));
+}
+
+
+/*! \brief Function to retrieve GhidViolationRenderer's GType identifier.
+ *
+ *  \par Function Description
+ *  Function to retrieve GhidViolationRenderer's GType identifier.
+ *  Upon first call, this registers the GhidViolationRenderer in the GType system.
+ *  Subsequently it returns the saved value from its first execution.
+ *
+ *  \return the GType identifier associated with GhidViolationRenderer.
+ */
+GType
+ghid_violation_renderer_get_type ()
+{
+  static GType ghid_violation_renderer_type = 0;
+
+  if (!ghid_violation_renderer_type)
+    {
+      static const GTypeInfo ghid_violation_renderer_info = {
+	sizeof (GhidViolationRendererClass),
+	NULL,			/* base_init */
+	NULL,			/* base_finalize */
+	(GClassInitFunc) ghid_violation_renderer_class_init,
+	NULL,			/* class_finalize */
+	NULL,			/* class_data */
+	sizeof (GhidViolationRenderer),
+	0,			/* n_preallocs */
+	NULL,			/* instance_init */
+      };
+
+      ghid_violation_renderer_type =
+	g_type_register_static (GTK_TYPE_CELL_RENDERER_TEXT, "GhidViolationRenderer",
+				&ghid_violation_renderer_info, 0);
+    }
+
+  return ghid_violation_renderer_type;
+}
+
+
+/*! \brief Convenience function to create a new violation renderer
+ *
+ *  \par Function Description
+ *  Convenience function which creates a GhidViolationRenderer.
+ *
+ *  \return  The GhidViolationRenderer created.
+ */
+GtkCellRenderer *
+ghid_violation_renderer_new (void)
+{
+  GhidViolationRenderer *renderer;
+
+  renderer = g_object_new (GHID_TYPE_VIOLATION_RENDERER,
+                           "ypad", 6,
+                           NULL);
+
+  return GTK_CELL_RENDERER (renderer);
+//  return gtk_cell_renderer_text_new ();
+}
+
+
+void
+ghid_drc_window_show (gboolean raise)
+{
+  GtkWidget *vbox, *hbox, *button, *scrolled_window;
+  GtkCellRenderer *violation_renderer;
+
+  if (drc_window)
+    {
+      if (raise)
+        gtk_window_present(GTK_WINDOW(drc_window));
+      return;
+    }
+
+ drc_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  g_signal_connect (G_OBJECT (drc_window), "destroy",
+		    G_CALLBACK (drc_destroy_cb), NULL);
+  g_signal_connect (G_OBJECT (drc_window), "configure_event",
+		    G_CALLBACK (drc_window_configure_event_cb), NULL);
+  gtk_window_set_title (GTK_WINDOW (drc_window), _("PCB DRC"));
+  gtk_window_set_wmclass (GTK_WINDOW (drc_window), "PCB_DRC", "PCB");
+  gtk_window_set_default_size (GTK_WINDOW (drc_window),
+			       ghidgui->drc_window_width,
+			       ghidgui->drc_window_height);
+
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+  gtk_container_add (GTK_CONTAINER (drc_window), vbox);
+
+  drc_list_model = gtk_list_store_new (NUM_DRC_COLUMNS,
+                                       G_TYPE_INT,      /* DRC_VIOLATION_NUM_COL    */
+                                       G_TYPE_STRING,   /* DRC_TITLE_COL            */
+                                       G_TYPE_STRING,   /* DRC_EXPLANATION_COL      */
+                                       G_TYPE_INT,      /* DRC_X_COORD_COL          */
+                                       G_TYPE_INT,      /* DRC_Y_COORD_COL          */
+                                       G_TYPE_INT,      /* DRC_ANGLE_COL            */
+                                       G_TYPE_DOUBLE,   /* DRC_MEASURED_VALUE_COL   */
+                                       G_TYPE_DOUBLE,   /* DRC_REQUIRED_VALUE_COL   */
+                                       G_TYPE_INT,      /* DRC_VALUE_DIGITS_COL     */
+                                       G_TYPE_STRING,   /* DRC_VALUE_UNITS_COL      */
+                                       G_TYPE_INT,      /* DRC_OBJECT_COUNT_COL     */
+#warning CHEATING HERE!
+  /* I happen to know I'm only putting 0 or 1 items in the lists of objects.
+     To do this properly requires some memory allocation and tracking to
+     avoid leaks! */
+#if 0
+                                       G_TYPE_POINTER,  /* DRC_OBJECT_ID_LIST_COL   */
+                                       G_TYPE_POINTER); /* DRC_OBJECT_TYPE_LIST_COL */
+#else
+                                       G_TYPE_LONG,     /* DRC_OBJECT_ID_LIST_COL   */
+                                       G_TYPE_INT);     /* DRC_OBJECT_TYPE_LIST_COL */
+#endif
+
+  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+  gtk_box_pack_start (GTK_BOX (vbox), scrolled_window,
+                      TRUE /* EXPAND */, TRUE /* FILL */, 0 /* PADDING */);
+
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+  drc_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (drc_list_model));
+  gtk_container_add (GTK_CONTAINER (scrolled_window), drc_list);
+
+  gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (drc_list), TRUE);
+  g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (drc_list)), "changed",
+                    G_CALLBACK (selection_changed_cb), NULL);
+
+  violation_renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (drc_list),
+                                               -1, /* APPEND */
+                                               _("No."), /* TITLE */
+                                               violation_renderer,
+                                               "text",           DRC_VIOLATION_NUM_COL,
+                                                NULL);
+
+  violation_renderer = ghid_violation_renderer_new ();
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (drc_list),
+                                               -1, /* APPEND */
+                                               _("Violation details"), /* TITLE */
+                                               violation_renderer,
+                                               "title",          DRC_TITLE_COL,
+                                               "explanation",    DRC_EXPLANATION_COL,
+                                               "x-coord",        DRC_X_COORD_COL,
+                                               "y-coord",        DRC_Y_COORD_COL,
+                                               "angle",          DRC_ANGLE_COL,
+                                               "measured-value", DRC_MEASURED_VALUE_COL,
+                                               "required-value", DRC_REQUIRED_VALUE_COL,
+                                               "value-digits",   DRC_VALUE_DIGITS_COL,
+                                               "value-units",    DRC_VALUE_UNITS_COL,
+                                                NULL);
+
+  hbox = gtk_hbutton_box_new ();
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+  button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
+  g_signal_connect (G_OBJECT (button), "clicked",
+		    G_CALLBACK (drc_close_cb), NULL);
+  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
+
+  gtk_widget_realize (drc_window);
+  if (Settings.AutoPlace)
+    gtk_widget_set_uposition (GTK_WIDGET (drc_window), 10, 10);
+  gtk_widget_show_all (drc_window);
+}
+
+#define UNIT1(value) (Settings.grid_units_mm ? ((value) / 100000.0 * 25.4) : ((value) / 100.0))
+#define UNIT(value) UNIT1(value) , (Settings.grid_units_mm ? "mm" : "mils")
+
+void ghid_drc_window_append_violation (DRC_VIOLATION *violation)
+{
+  GtkTreeIter iter;
+  long int ID = 0;
+  int type = NO_TYPE;
+
+  /* Ensure the required structures are setup */
+  ghid_drc_window_show (FALSE);
+
+  num_violations++;
+
+  /* Copy the violating object lists */
+#warning CHEATING HERE!
+  /* I happen to know I'm only putting 0 or 1 items in the lists of objects.
+     To do this properly requires some memory allocation and tracking to
+     avoid leaks! */
+  if (violation->object_count > 0)
+    {
+      ID = violation->object_id_list[0];
+      type = violation->object_type_list[0];
+    }
+
+  gtk_list_store_append (drc_list_model, &iter);
+  gtk_list_store_set (drc_list_model, &iter,
+                      DRC_VIOLATION_NUM_COL,    num_violations,
+                      DRC_TITLE_COL,            violation->title,
+                      DRC_EXPLANATION_COL,      violation->explanation,
+                      DRC_X_COORD_COL,          violation->x,
+                      DRC_Y_COORD_COL,          violation->y,
+                      DRC_ANGLE_COL,            violation->angle,
+                      DRC_MEASURED_VALUE_COL,   violation->measured_value,
+                      DRC_REQUIRED_VALUE_COL,   violation->required_value,
+                      DRC_VALUE_DIGITS_COL,     violation->value_digits,
+                      DRC_VALUE_UNITS_COL,      violation->value_units,
+                      DRC_OBJECT_COUNT_COL,     violation->object_count,
+                      DRC_OBJECT_ID_LIST_COL,   ID, /* violation->object_id_list, */
+                      DRC_OBJECT_TYPE_LIST_COL, type, /* violation->object_type_list, */
+                      -1);
+}
+
+void ghid_drc_window_reset_message (void)
+{
+  // printf ("RESET DRC WINDOW\n");
+  if (drc_list_model != NULL)
+    gtk_list_store_clear (drc_list_model);
+  num_violations = 0;
+}
+
+int ghid_drc_window_throw_dialog (void)
+{
+  // printf ("THROW DRC WINDOW\n");
+  ghid_drc_window_show (TRUE);
+  return 1;
+}
+
diff --git a/src/hid/gtk/gui.h b/src/hid/gtk/gui.h
index 771056b..f76e3b3 100644
--- a/src/hid/gtk/gui.h
+++ b/src/hid/gtk/gui.h
@@ -189,6 +189,8 @@ typedef struct
     top_window_height,
     log_window_width,
     log_window_height,
+    drc_window_width,
+    drc_window_height,
     keyref_window_width,
     keyref_window_height,
     library_window_width,
@@ -402,6 +404,14 @@ void ghid_dialog_print (HID *);
 
 int ghid_attribute_dialog (HID_Attribute *, int, HID_Attr_Val *, const char *, const char *);
 
+/* gui-drc-window.c */
+void ghid_drc_window_show (gboolean raise);
+void ghid_drc_window_reset_message (void);
+void ghid_drc_window_append_violation (DRC_VIOLATION *violation);
+//void ghid_drc_window_append_mesage (const char *fmt, ...);
+void ghid_drc_window_append_messagev (const char *fmt, va_list va);
+int ghid_drc_window_throw_dialog (void);
+
 /* gui-route-style function prototypes.
 */
   /* In gui-dialog-size.c */
diff --git a/src/hid/lesstif/main.c b/src/hid/lesstif/main.c
index d2b680b..99f9851 100644
--- a/src/hid/lesstif/main.c
+++ b/src/hid/lesstif/main.c
@@ -3928,7 +3928,8 @@ HID lesstif_gui = {
   lesstif_attribute_dialog,
   lesstif_show_item,
   lesstif_beep,
-  lesstif_progress
+  lesstif_progress,
+  0 /* lesstif_drc_gui */
 };
 
 #include "dolists.h"
diff --git a/src/hid/lpr/lpr.c b/src/hid/lpr/lpr.c
index cbf19c6..31d288e 100644
--- a/src/hid/lpr/lpr.c
+++ b/src/hid/lpr/lpr.c
@@ -163,7 +163,8 @@ HID lpr_hid = {
   0 /* lpr_attribute_dialog */ ,
   0 /* lpr_show_item */ ,
   0 /* lpr_beep */ ,
-  0 /* lpr_progress */
+  0 /* lpr_progress */ ,
+  0 /* lpr_drc_gui */
 };
 
 void
diff --git a/src/hid/nelma/nelma.c b/src/hid/nelma/nelma.c
index e548bc0..2dfe41a 100644
--- a/src/hid/nelma/nelma.c
+++ b/src/hid/nelma/nelma.c
@@ -1102,7 +1102,8 @@ HID             nelma_hid = {
 	0 /* nelma_attribute_dialog */ ,
 	0 /* nelma_show_item */ ,
 	0 /* nelma_beep */ ,
-	0			/* nelma_progress */
+	0 /* nelma_progress */ ,
+	0 /* nelma_drc_gui */
 };
 
 #include "dolists.h"
diff --git a/src/hid/png/png.c b/src/hid/png/png.c
index ae4c95f..aa9dc52 100644
--- a/src/hid/png/png.c
+++ b/src/hid/png/png.c
@@ -1376,7 +1376,8 @@ HID png_hid = {
   0 /* png_attribute_dialog */ ,
   0 /* png_show_item */ ,
   0 /* png_beep */ ,
-  0 /* png_progress */
+  0 /* png_progress */ ,
+  0 /* png_drc_gui */
 };
 
 #include "dolists.h"
diff --git a/src/hid/ps/eps.c b/src/hid/ps/eps.c
index be49202..3dc8510 100644
--- a/src/hid/ps/eps.c
+++ b/src/hid/ps/eps.c
@@ -663,7 +663,9 @@ static HID eps_hid = {
   0 /* eps_prompt_for */ ,
   0 /* eps_attribute_dialog */ ,
   0 /* eps_show_item */ ,
-  0				/* eps_beep */
+  0 /* eps_beep */ ,
+  0 /* eps_progress */ ,
+  0 /* eps_drc_gui */
 };
 
 void
diff --git a/src/hid/ps/ps.c b/src/hid/ps/ps.c
index cb96675..880b2ee 100644
--- a/src/hid/ps/ps.c
+++ b/src/hid/ps/ps.c
@@ -1203,7 +1203,8 @@ HID ps_hid = {
   0 /* ps_attribute_dialog */ ,
   0 /* ps_show_item */ ,
   0 /* ps_beep */ ,
-  0 /* ps_progress */
+  0 /* ps_progress */ ,
+  0 /* ps_drc_gui */
 };
 
 #include "dolists.h"

_______________________________________________
geda-user mailing list
geda-user@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-user