This patch allows symbols to be selected by clicking anywhere inside the symbol. Solid and hatched shapes can also be selected by clicking inside the shape. Hopefully, this eliminates some of the irritation caused by the current selection behavior.

Hollow shapes not inside a symbol must still be selected by clicking on the perimeter. I left it this way so that a user could put dotted line boxes around other shapes, and select those shapes without accidentally selecting the surrounding box. An example includes putting a dotted line box around a set of resistors to label them "no- pop." The user could subsequently select the resistors without selecting the surrounding box.

Currently, shapes composed of lines and arcs that form a closed shape must still be selected by clicking on the perimeter. Examples of these shapes include nand gates, nor gates, op-amps, etc... However, when these symbols get converted to paths, then clicking inside the shape will select it. If symbol selection behavior continues to be a source of irritation, symbol selection could revert to bounding-box?

Cheers,
Ed

From 88cd675bf09207503a7c66418ae1cd3a12090076 Mon Sep 17 00:00:00 2001
From: Edward Hennessy <ehen...@sbcglobal.net>
Date: Fri, 12 Dec 2008 04:41:59 -0800
Subject: [PATCH] Symbols now selectable by clicking inside their shapes.

This patch changes the selection behavior by allowing symbols to
be selected by clicking inside any contained shape.  This behavior
works for symbols with boxes, circles, and paths.
---
 libgeda/include/prototype_priv.h |    7 +++
 libgeda/src/Makefile.am          |    2 +
 libgeda/src/m_box.c              |   85 ++++++++++++++++++++++++++++++++++++++
 libgeda/src/m_circle.c           |   69 ++++++++++++++++++++++++++++++
 libgeda/src/o_box_basic.c        |   30 ++------------
 libgeda/src/o_circle_basic.c     |   13 +----
 libgeda/src/o_complex_basic.c    |   71 +++++++++++++++++++++++++++++++-
 libgeda/src/o_path_basic.c       |   20 +--------
 libgeda/src/s_path.c             |   37 ++++++++++++++++
 9 files changed, 278 insertions(+), 56 deletions(-)
 create mode 100644 libgeda/src/m_box.c
 create mode 100644 libgeda/src/m_circle.c

diff --git a/libgeda/include/prototype_priv.h b/libgeda/include/prototype_priv.h
index 7807cef..0342d13 100644
--- a/libgeda/include/prototype_priv.h
+++ b/libgeda/include/prototype_priv.h
@@ -51,10 +51,16 @@ SCM g_get_line_width(SCM object_smob);
 void g_init_page_smob(void);
 SCM g_get_page_filename(SCM page_smob);
 
+/* m_circle.c */
+double m_circle_shortest_distance (CIRCLE *circle, int x, int y, gboolean 
solid);
+
 /* m_bounds.c */
 void m_bounds_init(BOUNDS *bounds);
 void m_bounds_of_points(BOUNDS *bounds, sPOINT points[], gint count);
 
+/* m_box.c */
+double m_box_shortest_distance (BOX *box, int x, int y, gboolean solid);
+
 /* m_hatch.c */
 void m_hatch_polygon(GArray *points, gint angle, gint pitch, GArray *lines);
 
@@ -212,6 +218,7 @@ gchar* s_encoding_base64_decode (gchar* src, guint srclen, 
guint* dstlenp);
 
 /* s_path.c */
 void s_path_to_polygon(PATH *path, GArray *points);
+double s_path_shortest_distance (PATH *path, int x, int y, gboolean solid);
 
 /* s_textbuffer.c */
 TextBuffer *s_textbuffer_new (gchar *data, const gint size);
diff --git a/libgeda/src/Makefile.am b/libgeda/src/Makefile.am
index 78e025b..9d7450e 100644
--- a/libgeda/src/Makefile.am
+++ b/libgeda/src/Makefile.am
@@ -26,6 +26,8 @@ libgeda_la_SOURCES = \
        libgeda.c \
        m_basic.c \
        m_bounds.c \
+       m_box.c \
+       m_circle.c \
        m_hatch.c \
        m_polygon.c \
        m_transform.c \
diff --git a/libgeda/src/m_box.c b/libgeda/src/m_box.c
new file mode 100644
index 0000000..c95789d
--- /dev/null
+++ b/libgeda/src/m_box.c
@@ -0,0 +1,85 @@
+/* gEDA - GPL Electronic Design Automation
+ * libgeda - gEDA's library
+ * Copyright (C) 1998-2008 Ales Hvezda
+ * Copyright (C) 1998-2008 gEDA Contributors (see ChangeLog for details)
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111 USA
+ */
+
+/*! \file m_box.c
+ *
+ *  \brief  Low-level mathmatical functions for boxes
+ */
+
+#include <config.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "libgeda_priv.h"
+
+#ifdef HAVE_LIBDMALLOC
+#include <dmalloc.h>
+#endif
+
+/*! \brief Calculates the distance between the given point and the closest
+ *  point on the perimeter or interior of the box.
+ *
+ *  \param [in] box    The box.
+ *  \param [in] x      The x coordinate of the given point.
+ *  \param [in] y      The y coordinate of the given point.
+ *  \param [in] solid  TRUE if the box should be treated as solid, FALSE if
+ *  the box should be treated as hollow.
+ *  \return The shortest distance from the box to the point.  With a solid
+ *  shape, this function returns a distance of zero for interior points.  With
+ *  an invalid parameter, this function returns G_MAXDOUBLE.
+ */
+double m_box_shortest_distance (BOX *box, int x, int y, gboolean solid)
+{
+  double shortest_distance;
+  double x1, y1, x2, y2;
+  double dx, dy;
+
+  g_return_val_if_fail (box != NULL, G_MAXDOUBLE);
+
+  x1 = (double) min (box->upper_x, box->lower_x);
+  y1 = (double) min (box->upper_y, box->lower_y);
+  x2 = (double) max (box->upper_x, box->lower_x);
+  y2 = (double) max (box->upper_y, box->lower_y);
+
+  dx = min (((double)x) - x1, x2 - ((double)x));
+  dy = min (((double)y) - y1, y2 - ((double)y));
+
+  if (solid) {
+    dx = min (dx, 0);
+    dy = min (dy, 0);
+  }
+
+  if (dx < 0) {
+    if (dy < 0) {
+      shortest_distance = sqrt ((dx * dx) + (dy * dy));
+    } else {
+      shortest_distance = fabs (dx);
+    }
+  } else {
+    if (dy < 0) {
+      shortest_distance = fabs (dy);
+    } else {
+      shortest_distance = min (dx, dy);
+    }
+  }
+
+  return shortest_distance;
+}
+
diff --git a/libgeda/src/m_circle.c b/libgeda/src/m_circle.c
new file mode 100644
index 0000000..2c91473
--- /dev/null
+++ b/libgeda/src/m_circle.c
@@ -0,0 +1,69 @@
+/* gEDA - GPL Electronic Design Automation
+ * libgeda - gEDA's library
+ * Copyright (C) 1998-2008 Ales Hvezda
+ * Copyright (C) 1998-2008 gEDA Contributors (see ChangeLog for details)
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111 USA
+ */
+
+/*! \file m_circle.c
+ *
+ *  \brief Low-level mathmatical functions for circles
+ */
+
+#include <config.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "libgeda_priv.h"
+
+#ifdef HAVE_LIBDMALLOC
+#include <dmalloc.h>
+#endif
+
+/*! \brief Calculates the distance between the given point and the closest
+ * point on the perimeter or interior of the circle.
+ *
+ *  \param [in] circle  The circle.
+ *  \param [in] x       The x coordinate of the given point.
+ *  \param [in] y       The y coordinate of the given point.
+ *  \param [in] solid   TRUE if the circle should be treated as solid, FALSE if
+ *  the circle should be treated as hollow.
+ *  \return The shortest distance from the circle to the point.  With a solid
+ *  shape, this function returns a distance of zero for interior points.  With
+ *  an invalid parameter, this function returns G_MAXDOUBLE.
+ */
+double m_circle_shortest_distance (CIRCLE *circle, int x, int y, gboolean 
solid)
+{
+  double shortest_distance;
+  double distance_to_center;
+  double dx, dy;
+
+  g_return_val_if_fail (circle != NULL, G_MAXDOUBLE);
+
+  dx = ((double)x) - ((double)circle->center_x);
+  dy = ((double)y) - ((double)circle->center_y);
+
+  distance_to_center = sqrt ((dx * dx) + (dy * dy));
+
+  if (solid) {
+    shortest_distance = max (distance_to_center - circle->radius, 0);
+  } else {
+    shortest_distance = fabs (distance_to_center - circle->radius);
+  }
+
+  return shortest_distance;
+}
+
diff --git a/libgeda/src/o_box_basic.c b/libgeda/src/o_box_basic.c
index 48236a5..803b49e 100644
--- a/libgeda/src/o_box_basic.c
+++ b/libgeda/src/o_box_basic.c
@@ -1298,39 +1298,17 @@ void o_box_print_hatch(TOPLEVEL *toplevel, FILE *fp,
  *  \param [in] object  The box OBJECT.
  *  \param [in] x       The x coordinate of the given point.
  *  \param [in] y       The y coordinate of the given point.
- *  \return The shortest distance from the object to the point. With an 
+ *  \return The shortest distance from the object to the point. With an
  *  invalid parameter, this function returns G_MAXDOUBLE.
  */
 double o_box_shortest_distance (OBJECT *object, int x, int y)
 {
-  double shortest_distance;
-  double x1, y1, x2, y2;
-  double dx, dy;
+  gboolean solid;
 
   g_return_val_if_fail (object->box != NULL, G_MAXDOUBLE);
 
-  x1 = (double) min (object->box->upper_x, object->box->lower_x);
-  y1 = (double) min (object->box->upper_y, object->box->lower_y);
-  x2 = (double) max (object->box->upper_x, object->box->lower_x);
-  y2 = (double) max (object->box->upper_y, object->box->lower_y);
+  solid = object->fill_type != FILLING_HOLLOW;    /* FIXME */
 
-  dx = min (((double)x) - x1, x2 - ((double)x));
-  dy = min (((double)y) - y1, y2 - ((double)y));
-
-  if (dx < 0) {
-    if (dy < 0) {
-      shortest_distance = sqrt ((dx * dx) + (dy * dy));
-    } else {
-      shortest_distance = fabs (dx);
-    }
-  } else {
-    if (dy < 0) {
-      shortest_distance = fabs (dy);
-    } else {
-      shortest_distance = min (dx, dy);
-    }
-  }
-
-  return shortest_distance;
+  return m_box_shortest_distance (object->box, x, y, solid);
 }
 
diff --git a/libgeda/src/o_circle_basic.c b/libgeda/src/o_circle_basic.c
index ceeaa92..d310336 100644
--- a/libgeda/src/o_circle_basic.c
+++ b/libgeda/src/o_circle_basic.c
@@ -1113,19 +1113,12 @@ void o_circle_print_hatch(TOPLEVEL *toplevel, FILE *fp,
  */
 double o_circle_shortest_distance (OBJECT *object, int x, int y)
 {
-  double shortest_distance;
-  double distance_to_center;
-  double dx, dy;
+  gboolean solid;
 
   g_return_val_if_fail (object->circle != NULL, G_MAXDOUBLE);
 
-  dx = ((double)x) - ((double)object->circle->center_x);
-  dy = ((double)y) - ((double)object->circle->center_y);
+  solid = object->fill_type != FILLING_HOLLOW;    /* FIXME */
 
-  distance_to_center = sqrt ((dx * dx) + (dy * dy));
-
-  shortest_distance = fabs (distance_to_center - object->circle->radius);
-
-  return shortest_distance;
+  return m_circle_shortest_distance (object->circle, x, y, solid);
 }
 
diff --git a/libgeda/src/o_complex_basic.c b/libgeda/src/o_complex_basic.c
index 37f580e..81440d5 100644
--- a/libgeda/src/o_complex_basic.c
+++ b/libgeda/src/o_complex_basic.c
@@ -44,6 +44,8 @@
 /*! Default setting for complex draw function. */
 void (*complex_draw_func)() = NULL;
 
+static double special_shortest_distance (OBJECT *object, int x, int y);
+
 /*! \brief Return the bounds of the given object.
  *  \par Given an object, calculate the bounds coordinates.
  *  \param [in] toplevel The toplevel structure.
@@ -1553,10 +1555,77 @@ double o_complex_shortest_distance (OBJECT *object, int 
x, int y)
        iter != NULL; iter= g_list_next (iter)) {
     OBJECT *obj = iter->data;
 
-    distance = o_shortest_distance (obj, x, y);
+    distance = special_shortest_distance (obj, x, y);
     shortest_distance = min (shortest_distance, distance);
   }
 
   return shortest_distance;
 }
 
+/*! \brief Calculates the distance between the given point and the closest
+ *  point on a given object inside a complex object.
+ *
+ *  This function calculates the distance from a point to an object within
+ *  a complex object.  These objects are treated as a special case.  All
+ *  closed shapes are treated as solid.  This way, the user can select a
+ *  schematic symbol by clicking inside the body of the symbol.
+ *
+ *  \param [in] object The given object.
+ *  \param [in] x      The x coordinate of the given point.
+ *  \param [in] y      The y coordinate of the given point.
+ *  \return The shortest distance from the object to the point. If the
+ *  distance cannot be calculated, this function returns a really large
+ *  number (G_MAXDOUBLE).  If an error occurs, this function returns
+ *  G_MAXDOUBLE.
+ */
+static double special_shortest_distance (OBJECT *object, int x, int y)
+{
+  double shortest_distance = G_MAXDOUBLE;
+
+  g_return_val_if_fail (object != NULL, G_MAXDOUBLE);
+
+  switch(object->type) {
+    case OBJ_BUS:
+    case OBJ_NET:
+    case OBJ_PIN:
+    case OBJ_LINE:
+      shortest_distance = o_line_shortest_distance (object, x, y);
+      break;
+
+    case OBJ_BOX:
+      shortest_distance = m_box_shortest_distance (object->box, x, y, TRUE);
+      break;
+
+    case OBJ_PICTURE:
+      shortest_distance = o_picture_shortest_distance (object, x, y);
+      break;
+
+    case OBJ_CIRCLE:
+      shortest_distance = m_circle_shortest_distance (object->circle, x, y, 
TRUE);
+      break;
+
+    case OBJ_PLACEHOLDER:
+    case OBJ_COMPLEX:
+      shortest_distance = o_complex_shortest_distance (object, x, y);
+      break;
+
+    case OBJ_TEXT:
+      shortest_distance = o_text_shortest_distance (object, x, y);
+      break;
+
+    case OBJ_PATH:
+      shortest_distance = s_path_shortest_distance (object->path, x, y, TRUE);
+      break;
+
+    case OBJ_ARC:
+      shortest_distance = o_arc_shortest_distance (object, x, y);
+      break;
+
+    default:
+      g_critical ("o_shortest_distance: object %p has bad type '%c'\n",
+                  object, object->type);
+  }
+
+  return shortest_distance;
+}
+
diff --git a/libgeda/src/o_path_basic.c b/libgeda/src/o_path_basic.c
index 172da4f..fdb1036 100644
--- a/libgeda/src/o_path_basic.c
+++ b/libgeda/src/o_path_basic.c
@@ -1046,28 +1046,10 @@ void o_path_print(TOPLEVEL *toplevel, FILE *fp, OBJECT 
*o_current,
  */
 double o_path_shortest_distance (OBJECT *object, int x, int y)
 {
-  double shortest_distance = G_MAXDOUBLE;
-  GArray *points;
   gboolean solid;
 
-  points = g_array_new (FALSE, FALSE, sizeof (sPOINT));
-
-  s_path_to_polygon (object->path, points);
-
   solid = object->fill_type != FILLING_HOLLOW;    /* FIXME */
 
-  if (!solid) {
-    shortest_distance = m_polygon_shortest_distance (points, x, y, FALSE);
-
-  } else if (m_polygon_interior_point (points, x, y)) {
-    shortest_distance = 0;
-
-  } else {
-    shortest_distance = m_polygon_shortest_distance (points, x, y, TRUE);
-  }
-
-  g_array_free (points, TRUE);
-
-  return shortest_distance;
+  return s_path_shortest_distance (object->path, x, y, solid);
 }
 
diff --git a/libgeda/src/s_path.c b/libgeda/src/s_path.c
index ab94fef..265d3e1 100644
--- a/libgeda/src/s_path.c
+++ b/libgeda/src/s_path.c
@@ -748,3 +748,40 @@ void s_path_to_polygon (PATH *path, GArray *points)
     }
   }
 }
+
+/*! \brief Calculates the distance between the given point and the closest
+ *  point on the given path segment.
+ *
+ *  \param [in] path    The path.
+ *  \param [in] x       The x coordinate of the given point.
+ *  \param [in] y       The y coordinate of the given point.
+ *  \param [in] solid   TRUE if the path should be treated as solid, FALSE if
+ *  the path should be treated as hollow.
+ *  \return The shortest distance from the path to the point.  With a solid
+ *  shape, this function returns a distance of zero for interior points.  With
+ *  an invalid parameter, this function returns G_MAXDOUBLE.
+ */
+double s_path_shortest_distance (PATH *path, int x, int y, gboolean solid)
+{
+  double shortest_distance = G_MAXDOUBLE;
+  GArray *points;
+
+  points = g_array_new (FALSE, FALSE, sizeof (sPOINT));
+
+  s_path_to_polygon (path, points);
+
+  if (!solid) {
+    shortest_distance = m_polygon_shortest_distance (points, x, y, FALSE);
+
+  } else if (m_polygon_interior_point (points, x, y)) {
+    shortest_distance = 0;
+
+  } else {
+    shortest_distance = m_polygon_shortest_distance (points, x, y, TRUE);
+  }
+
+  g_array_free (points, TRUE);
+
+  return shortest_distance;
+}
+
-- 
1.5.4.3


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

Reply via email to