[dia] [custom] Fix some subshape cases and add svg:rect:(rx|ry)



commit b27a03ffe36e94f1a492cf817e9d25d5f37f1040
Author: Hans Breuer <hans breuer org>
Date:   Sun Sep 9 12:59:49 2012 +0200

    [custom] Fix some subshape cases and add svg:rect:(rx|ry)
    
    svg:image and svg:ellipse were not properly handles as subshapes:
    only the position was transformed, but not the size.
    
    Additionally there is <can-parent/> and some robustness improvement
    for broken <svg:image/> definitions.

 doc/custom-shapes              |    9 +++++-
 objects/custom/custom_object.c |   60 ++++++++++++++++++++++++++++++----------
 objects/custom/shape_info.c    |   29 ++++++++++++++++--
 objects/custom/shape_info.h    |    2 +
 4 files changed, 80 insertions(+), 20 deletions(-)
---
diff --git a/doc/custom-shapes b/doc/custom-shapes
index 9edf286..02085c4 100644
--- a/doc/custom-shapes
+++ b/doc/custom-shapes
@@ -91,6 +91,10 @@ distorted.  The three possibilities are:
 The last option allows you to specify a range of allowable amounts of
 distortion, which may be useful in some cases.
 
+The can-parent element allows to enable parenting for a shape. This is
+only useful for rectangular shapes, which should work as a container
+of other shapes or objects. So typical shapes wont have it.
+
 The textbox element allows you to associate some text with
 the shape.  The syntax is:
   <textbox x1="left" y1="top" x2="right" y2="bottom"/>
@@ -178,9 +182,12 @@ The recognised drawing elements are:
   This is a polygon.  The points argument has the same format as the
   polyline.
 
-<svg:rect x1="..." y1="..." width="..." height="..."/>
+<svg:rect x1="..." y1="..." width="..." height="..." rx="..." ry="..."/>
   This is a rectangle.  The upper left corner is (x1,y1), and the lower
   right corner is (x1+width,y1+height).
+  To get rounded corners either rx or ry or both can be given for the
+  single supported corner radius. If both are given the average gets
+  used.
 
 <svg:image x1="..." y1="..." width="..." height="..." xlink:href="..." />
   This is an external image.  The upper left corner is (x1,y1), and the 
diff --git a/objects/custom/custom_object.c b/objects/custom/custom_object.c
index dc709b8..72a80cb 100644
--- a/objects/custom/custom_object.c
+++ b/objects/custom/custom_object.c
@@ -518,6 +518,24 @@ transform_length(Custom *custom, real length)
 }
 
 static void
+transform_size(Custom *custom, real w1, real h1, real *w2, real *h2)
+{
+  if (custom->current_subshape != NULL) {
+    GraphicElementSubShape* subshape = custom->current_subshape;
+    g_assert (custom->subscale > 0.0 && subshape->default_scale > 0.0);
+    if (w2)
+      *w2 = w1 * custom->subscale * subshape->default_scale;
+    if (h2)
+      *h2 = h1 * custom->subscale * subshape->default_scale;
+  } else {
+    if (w2)
+      *w2 = w1 * fabs(custom->xscale);
+    if (h2)
+      *h2 = h1 * fabs(custom->yscale);
+  }
+}
+
+static void
 transform_coord(Custom *custom, const Point *p1, Point *out)
 {
   if (custom->current_subshape != NULL) {
@@ -906,9 +924,11 @@ custom_draw_element(GraphicElement* el, Custom *custom, DiaRenderer *renderer,
 {
   DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
   Point p1, p2;
+  real width, height;
   real coord;
   int i;
-    
+  real radius;
+
   if (el->any.s.line_width != (*cur_line)) {
     (*cur_line) = el->any.s.line_width;
     renderer_ops->set_linewidth(renderer,
@@ -975,6 +995,7 @@ custom_draw_element(GraphicElement* el, Custom *custom, DiaRenderer *renderer,
   case GE_RECT:
     transform_coord(custom, &el->rect.corner1, &p1);
     transform_coord(custom, &el->rect.corner2, &p2);
+    radius = transform_length(custom, el->rect.corner_radius);
     if (p1.x > p2.x) {
       coord = p1.x;
       p1.x = p2.x;
@@ -985,10 +1006,11 @@ custom_draw_element(GraphicElement* el, Custom *custom, DiaRenderer *renderer,
       p1.y = p2.y;
       p2.y = coord;
     }
+    /* the renderer implementation will use simple rect with a small enough radius */
     if (custom->show_background && el->any.s.fill != DIA_SVG_COLOUR_NONE)
-      renderer_ops->fill_rect(renderer, &p1, &p2, bg);
+      renderer_ops->fill_rounded_rect(renderer, &p1, &p2, bg, radius);
     if (el->any.s.stroke != DIA_SVG_COLOUR_NONE)
-      renderer_ops->draw_rect(renderer, &p1, &p2, fg);
+      renderer_ops->draw_rounded_rect(renderer, &p1, &p2, fg, radius);
     break;
   case GE_TEXT:
     text_set_height (el->text.object, transform_length (custom, el->text.s.font_height));
@@ -999,23 +1021,19 @@ custom_draw_element(GraphicElement* el, Custom *custom, DiaRenderer *renderer,
     break;
   case GE_ELLIPSE:
     transform_coord(custom, &el->ellipse.center, &p1);
+    transform_size(custom, el->ellipse.width, el->ellipse.height, &width, &height);
     if (custom->show_background && el->any.s.fill != DIA_SVG_COLOUR_NONE)
-      renderer_ops->fill_ellipse(renderer, &p1,
-				   el->ellipse.width * fabs(custom->xscale),
-				   el->ellipse.height * fabs(custom->yscale),
-				   bg);
+      renderer_ops->fill_ellipse(renderer, &p1, width,  height, bg);
     if (el->any.s.stroke != DIA_SVG_COLOUR_NONE)
-      renderer_ops->draw_ellipse(renderer, &p1,
-				   el->ellipse.width * fabs(custom->xscale),
-				   el->ellipse.height * fabs(custom->yscale),
-				   fg);
+      renderer_ops->draw_ellipse(renderer, &p1, width, height, fg);
     break;
   case GE_IMAGE:
     transform_coord(custom, &el->image.topleft, &p1);
+    /* to scale correctly also for subshape some extra hoops */
+    transform_size(custom, el->image.width, el->image.height, &width, &height);
     renderer_ops->draw_image(renderer, &p1,
-			       el->image.width * fabs(custom->xscale),
-			       el->image.height * fabs(custom->yscale),
-			       el->image.image);
+			     width, height,
+			     el->image.image);
     break;
   case GE_PATH:
     g_array_set_size(barr, el->path.npoints);
@@ -1351,7 +1369,16 @@ custom_update_data(Custom *custom, AnchorShape horiz, AnchorShape vert)
   for (tmp = custom->info->display_list; tmp != NULL; tmp = tmp->next) {
     GraphicElement *el = tmp->data;
     Rectangle rect;
+    /* Line width handling/behavior for custom objects is special. Instead of
+     * directly using the given width some ratio with the shape global custom
+     * border_width gets calculated - to allow influencing all line width used
+     * in a complex shape (and not brea backward compatibility). With
     real lwfactor = custom->border_width / 2;
+     * we get traces in the diagram at high zoom levels, so use something more
+     * safe for the bounding box calculation     
+     */
+    real lwfactor = el->any.s.line_width == custom->border_width 
+                  ? 1.0 : custom->border_width;
 
     switch(el->type) {
     case GE_SUBSHAPE :
@@ -1540,7 +1567,7 @@ custom_create(Point *startpoint,
   custom = g_new0_ext (Custom, info->ext_attr_size);
   elem = &custom->element;
   obj = &elem->object;
-  
+
   obj->type = info->object_type;
 
   obj->ops = &custom_ops;
@@ -1552,6 +1579,8 @@ custom_create(Point *startpoint,
 
   custom->info = info;
   
+  obj->flags |= info->object_flags;
+
   custom->old_subscale = 1.0;
   custom->subscale = 1.0;
   custom->current_subshape = NULL;
@@ -1638,6 +1667,7 @@ custom_copy(Custom *custom)
 
   element_copy(elem, newelem);
   newcustom->info = custom->info;
+  newobj->flags = custom->element.object.flags;
 
   newcustom->padding = custom->padding;
   newcustom->current_subshape = NULL; /* it's temporary state, don't copy from wrong object */
diff --git a/objects/custom/shape_info.c b/objects/custom/shape_info.c
index d120a01..bdc0a72 100644
--- a/objects/custom/shape_info.c
+++ b/objects/custom/shape_info.c
@@ -315,6 +315,7 @@ parse_svg_node(ShapeInfo *info, xmlNodePtr node, xmlNsPtr svg_ns,
       g_array_free(arr, TRUE);
     } else if (!xmlStrcmp(node->name, (const xmlChar *)"rect")) {
       GraphicElementRect *rect = g_new0(GraphicElementRect, 1);
+      real corner_radius = 0.0;
 
       el = (GraphicElement *)rect;
       rect->type = GE_RECT;
@@ -338,6 +339,22 @@ parse_svg_node(ShapeInfo *info, xmlNodePtr node, xmlNsPtr svg_ns,
         rect->corner2.y = rect->corner1.y + g_ascii_strtod((gchar *) str, NULL);
         xmlFree(str);
       }
+      str = xmlGetProp(node, (const xmlChar *)"rx");
+      if (str) {
+        corner_radius = g_ascii_strtod((gchar *) str, NULL);
+        xmlFree(str);
+      }
+      str = xmlGetProp(node, (const xmlChar *)"ry");
+      if (str) {
+        if(corner_radius != 0.0) {
+          /* calculate the mean value of rx and ry */
+          corner_radius = (corner_radius+g_ascii_strtod((gchar *) str, NULL))/2;
+        } else {
+          corner_radius = g_ascii_strtod((gchar *) str, NULL);
+        }
+        xmlFree(str);
+      }
+      rect->corner_radius = corner_radius;
     } else if (!xmlStrcmp(node->name, (const xmlChar *)"text")) {
 
       GraphicElementText *text = g_new(GraphicElementText, 1);
@@ -465,14 +482,14 @@ parse_svg_node(ShapeInfo *info, xmlNodePtr node, xmlNsPtr svg_ns,
 
           image->image = dia_image_load(imgfn);
 	}
-        /* w/o the image we would crash later */
-        if (!image->image) {
+        if (!image->image)
           g_warning("failed to load image file %s", imgfn ? imgfn : "(data:)");
-          image->image = dia_image_get_broken();
-        }
         g_free(imgfn);
         xmlFree(str);
       }
+      /* w/o the image we would crash later */
+      if (!image->image)
+        image->image = dia_image_get_broken();
     } else if (!xmlStrcmp(node->name, (const xmlChar *)"g")) {
       if (!is_subshape(node)) {
           /* add elements from the group element */
@@ -586,6 +603,7 @@ update_bounds(ShapeInfo *info)
     case GE_RECT:
       check_point(info, &(el->rect.corner1));
       check_point(info, &(el->rect.corner2));
+      /* el->rect.corner_radius has no infulence on the bounding rectangle */
       break;
     case GE_TEXT:
       check_point(info, &(el->text.anchor));
@@ -693,6 +711,7 @@ load_shape_info(const gchar *filename, ShapeInfo *preload)
   info->default_width = 0.0;
   info->default_height = 0.0;
   info->main_cp = -1;
+  info->object_flags = 0;
 
   i = 0;
   for (node = root->xmlChildrenNode; node != NULL; node = node->next) {
@@ -760,6 +779,8 @@ load_shape_info(const gchar *filename, ShapeInfo *preload)
       info->nconnections = arr->len;
       info->connections = (Point *)arr->data;
       g_array_free(arr, FALSE);
+    } else if (node->ns == shape_ns && !xmlStrcmp(node->name, (const xmlChar *)"can-parent")) {
+      info->object_flags |= DIA_OBJECT_CAN_PARENT;
     } else if (node->ns == shape_ns && !xmlStrcmp(node->name, (const xmlChar *)"textbox")) {
       xmlChar *str;
       
diff --git a/objects/custom/shape_info.h b/objects/custom/shape_info.h
index 7971792..870fbae 100644
--- a/objects/custom/shape_info.h
+++ b/objects/custom/shape_info.h
@@ -80,6 +80,7 @@ struct _GraphicElementPoly {
 struct _GraphicElementRect {
   SHAPE_INFO_COMMON;
   Point corner1, corner2;
+  real corner_radius;
 };
 
 struct _GraphicElementEllipse {
@@ -176,6 +177,7 @@ struct _ShapeInfo {
   int nconnections;
   Point *connections;
   int main_cp; /* The cp that gets connections from the whole object */
+  int object_flags;
   Rectangle shape_bounds;
   gboolean has_text;
   gboolean resize_with_text;



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