dia r3883 - in trunk: lib objects/custom



Author: lclausen
Date: Tue Feb 12 17:15:00 2008
New Revision: 3883
URL: http://svn.gnome.org/viewvc/dia?rev=3883&view=rev

Log:
Patch from Marcel Toele for subshapes.


Added:
   trunk/lib/units.c
   trunk/lib/units.h
Modified:
   trunk/lib/Makefile.am
   trunk/lib/diatypes.h
   trunk/lib/geometry.c
   trunk/lib/geometry.h
   trunk/lib/widgets.c
   trunk/lib/widgets.h
   trunk/objects/custom/custom_object.c
   trunk/objects/custom/shape_info.c
   trunk/objects/custom/shape_info.h

Modified: trunk/lib/Makefile.am
==============================================================================
--- trunk/lib/Makefile.am	(original)
+++ trunk/lib/Makefile.am	Tue Feb 12 17:15:00 2008
@@ -101,6 +101,8 @@
 		objchange.h \
 		widgets.c \
 		widgets.h \
+		units.c \
+		units.h \
 		dia_image.c \
 		dia_image.h \
 		intl.c \

Modified: trunk/lib/diatypes.h
==============================================================================
--- trunk/lib/diatypes.h	(original)
+++ trunk/lib/diatypes.h	Tue Feb 12 17:15:00 2008
@@ -21,6 +21,8 @@
 #ifndef TYPES_H
 #define TYPES_H
 
+#include "units.h"
+
 /* In diagramdata.h: */
 typedef struct _DiagramData DiagramData;
 typedef struct _Layer Layer;
@@ -97,7 +99,6 @@
 typedef struct _DiaFontClass DiaFontClass;
 
 /* In geometry.h: */
-typedef struct _DiaUnitDef            DiaUnitDef;
 typedef struct _Point Point;
 typedef struct _Rectangle Rectangle;
 typedef struct _IntRectangle IntRectangle;

Modified: trunk/lib/geometry.c
==============================================================================
--- trunk/lib/geometry.c	(original)
+++ trunk/lib/geometry.c	Tue Feb 12 17:15:00 2008
@@ -28,25 +28,9 @@
 #define G_INLINE_FUNC extern
 #define G_CAN_INLINE 1
 #include "geometry.h"
-#include "object.h"
-
 
-/* from gnome-libs/libgnome/gnome-paper.c */
-const DiaUnitDef units[] =
-{
-  /* XXX does anyone *really* measure paper size in feet?  meters? */
-
-  /* human name, abreviation, points per unit */
-  { "Centimeter", "cm", 28.346457, 2 },
-  { "Decimeter",  "dm", 283.46457, 3 },
-  { "Feet",       "ft", 864, 4 },
-  { "Inch",       "in", 72, 3 },
-  { "Meter",      "m",  2834.6457, 4 },
-  { "Millimeter", "mm", 2.8346457, 2 },
-  { "Point",      "pt", 1, 2 },
-  { "Pica",       "pi", 12, 2 },
-  { 0 }
-};
+#include "object.h"
+#include "units.h"
 
 void
 rectangle_union(Rectangle *r1, const Rectangle *r2)

Modified: trunk/lib/geometry.h
==============================================================================
--- trunk/lib/geometry.h	(original)
+++ trunk/lib/geometry.h	Tue Feb 12 17:15:00 2008
@@ -66,16 +66,6 @@
 
 G_BEGIN_DECLS
 
-/** Definitions of miscellaneous units.  Note that all sizes used
- * internally are in cm, units should only be used for display purposes.
- */
-struct _DiaUnitDef {
-  char* name;
-  char* unit;
-  float factor;
-  int digits; /** Number of digits after the decimal separator */
-};
-extern const DiaUnitDef units[];
 
 /*
   Coordinate system used:

Added: trunk/lib/units.c
==============================================================================
--- (empty file)
+++ trunk/lib/units.c	Tue Feb 12 17:15:00 2008
@@ -0,0 +1,19 @@
+
+#include "units.h"
+
+/* from gnome-libs/libgnome/gnome-paper.c */
+const DiaUnitDef units[] =
+{
+  /* XXX does anyone *really* measure paper size in feet?  meters? */
+
+  /* human name, abreviation, points per unit */
+  { "Centimeter", "cm", 28.346457, 2 },
+  { "Decimeter",  "dm", 283.46457, 3 },
+  { "Feet",       "ft", 864, 4 },
+  { "Inch",       "in", 72, 3 },
+  { "Meter",      "m",  2834.6457, 4 },
+  { "Millimeter", "mm", 2.8346457, 2 },
+  { "Point",      "pt", 1, 2 },
+  { "Pica",       "pi", 12, 2 },
+  { 0 }
+};

Added: trunk/lib/units.h
==============================================================================
--- (empty file)
+++ trunk/lib/units.h	Tue Feb 12 17:15:00 2008
@@ -0,0 +1,44 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * 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-1307, USA.
+ */
+#ifndef UNITS_H
+#define UNITS_H
+
+#include <config.h>
+
+typedef enum {
+  DIA_UNIT_CENTIMETER,
+  DIA_UNIT_DECIMETER,
+  DIA_UNIT_FEET,
+  DIA_UNIT_INCH,
+  DIA_UNIT_METER,
+  DIA_UNIT_MILLIMETER,
+  DIA_UNIT_POINT,
+  DIA_UNIT_PICA,
+} DiaUnit;
+
+typedef struct _DiaUnitDef DiaUnitDef;
+struct _DiaUnitDef {
+  char* name;
+  char* unit;
+  float factor;
+  int digits; /** Number of digits after the decimal separator */
+};
+
+extern const DiaUnitDef units[];
+
+#endif /* UNITS_H */

Modified: trunk/lib/widgets.c
==============================================================================
--- trunk/lib/widgets.c	(original)
+++ trunk/lib/widgets.c	Tue Feb 12 17:15:00 2008
@@ -21,6 +21,7 @@
 #include "intl.h"
 #undef GTK_DISABLE_DEPRECATED /* GtkOptionMenu, ... */
 #include "widgets.h"
+#include "units.h"
 #include "message.h"
 #include "dia_dirs.h"
 #include "arrows.h"

Modified: trunk/lib/widgets.h
==============================================================================
--- trunk/lib/widgets.h	(original)
+++ trunk/lib/widgets.h	Tue Feb 12 17:15:00 2008
@@ -33,7 +33,6 @@
 #include <gtk/gtkmenuitem.h>
 
 #include "diatypes.h"
-
 #include "font.h"
 #include "color.h"
 #include "arrows.h"
@@ -169,17 +168,6 @@
 typedef struct _DiaUnitSpinner DiaUnitSpinner;
 typedef struct _DiaUnitSpinnerClass DiaUnitSpinnerClass;
 
-typedef enum {
-  DIA_UNIT_CENTIMETER,
-  DIA_UNIT_DECIMETER,
-  DIA_UNIT_FEET,
-  DIA_UNIT_INCH,
-  DIA_UNIT_METER,
-  DIA_UNIT_MILLIMETER,
-  DIA_UNIT_POINT,
-  DIA_UNIT_PICA,
-} DiaUnit;
-
 struct _DiaUnitSpinner {
   GtkSpinButton parent;
 

Modified: trunk/objects/custom/custom_object.c
==============================================================================
--- trunk/objects/custom/custom_object.c	(original)
+++ trunk/objects/custom/custom_object.c	Tue Feb 12 17:15:00 2008
@@ -4,6 +4,9 @@
  * Custom Objects -- objects defined in XML rather than C.
  * Copyright (C) 1999 James Henstridge.
  *
+ * Non-uniform scaling/subshape support by Marcel Toele.
+ * Modifications (C) 2007 Kern Automatiseringsdiensten BV.
+ *
  * 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
@@ -50,10 +53,6 @@
 
 #include "pixmaps/custom.xpm"
 
-#define DEFAULT_WIDTH 2.0
-#define DEFAULT_HEIGHT 2.0
-#define DEFAULT_BORDER 0.25
-
 /* used when resizing to decide which side of the shape to expand/shrink */
 typedef enum {
   ANCHOR_MIDDLE,
@@ -71,6 +70,17 @@
   real xscale, yscale;
   real xoffs,  yoffs;
 
+  /* The subscale variables
+   * The old_subscale is used for interactive 
+   * (shift-pressed) scaling
+   */
+  real subscale;
+  real old_subscale;
+  /* this is sort of a hack, passing a temporary value
+     using this field, but otherwise 
+     subshapes are going to need major code refactoring: */
+  GraphicElementSubShape* current_subshape;
+  
   ConnectionPoint *connections;
   real border_width;
   Color border_color;
@@ -111,6 +121,14 @@
 					ModifierKeys modifiers);
 static ObjectChange* custom_move(Custom *custom, Point *to);
 static void custom_draw(Custom *custom, DiaRenderer *renderer);
+static void custom_draw_displaylist(GList *display_list, Custom *custom,
+				DiaRenderer *renderer, GArray *arr, GArray *barr, real* cur_line,
+				real* cur_dash, LineCaps* cur_caps, LineJoin* cur_join, 
+				LineStyle* cur_style);
+static void custom_draw_element(GraphicElement* el, Custom *custom,
+				DiaRenderer *renderer, GArray *arr, GArray *barr, real* cur_line,
+				real* cur_dash, LineCaps* cur_caps, LineJoin* cur_join, 
+				LineStyle* cur_style, Color* fg, Color* bg);
 static void custom_update_data(Custom *custom, AnchorShape h, AnchorShape v);
 static void custom_reposition_text(Custom *custom, GraphicElementText *text);
 static DiaObject *custom_create(Point *startpoint,
@@ -178,6 +196,9 @@
     N_("Flip horizontal"), NULL, NULL },
   { "flip_vertical", PROP_TYPE_BOOL, PROP_FLAG_VISIBLE|PROP_FLAG_OPTIONAL,
     N_("Flip vertical"), NULL, NULL },
+  
+  { "subscale", PROP_TYPE_REAL, PROP_FLAG_OPTIONAL,
+    N_("Scale of the subshapes"), NULL, NULL },
   PROP_DESC_END
 };
 
@@ -203,6 +224,9 @@
     N_("Flip horizontal"), NULL, NULL },
   { "flip_vertical", PROP_TYPE_BOOL, PROP_FLAG_VISIBLE|PROP_FLAG_OPTIONAL,
     N_("Flip vertical"), NULL, NULL },
+  
+  { "subscale", PROP_TYPE_REAL, PROP_FLAG_OPTIONAL,
+    N_("Scale of the subshapes"), NULL, NULL },
   PROP_DESC_END
 };
 
@@ -216,6 +240,7 @@
     offsetof(Custom, line_style), offsetof(Custom, dashlength) },
   { "flip_horizontal", PROP_TYPE_BOOL, offsetof(Custom, flip_h) },
   { "flip_vertical", PROP_TYPE_BOOL, offsetof(Custom, flip_v) },
+  { "subscale", PROP_TYPE_REAL, offsetof(Custom, subscale) },
   { NULL, 0, 0 }
 };
 
@@ -229,6 +254,7 @@
     offsetof(Custom, line_style), offsetof(Custom, dashlength) },
   { "flip_horizontal", PROP_TYPE_BOOL, offsetof(Custom, flip_h) },
   { "flip_vertical", PROP_TYPE_BOOL, offsetof(Custom, flip_v) },
+  { "subscale", PROP_TYPE_REAL, offsetof(Custom, subscale) },
   {"text",PROP_TYPE_TEXT,offsetof(Custom,text)},
   {"text_font",PROP_TYPE_FONT,offsetof(Custom,attrs.font)},
   {PROP_STDNAME_TEXT_HEIGHT, PROP_STDTYPE_TEXT_HEIGHT,offsetof(Custom,attrs.height)},
@@ -385,12 +411,105 @@
   }
 }
 
+static void
+transform_subshape_coord(Custom *custom, GraphicElementSubShape* subshape,
+                         const Point *p1, Point *out)
+{
+  if (subshape->default_scale == 0.0) {
+    ShapeInfo *info = custom->info;
+    real svg_width = info->shape_bounds.right - info->shape_bounds.left;
+    real svg_height = info->shape_bounds.bottom - info->shape_bounds.top;
+    
+    subshape->default_scale = info->default_width / svg_width /
+                                   units[prefs_get_length_unit()].factor;
+  }
+  
+  real scale = custom->subscale * subshape->default_scale;
+  	      
+  coord cx = 0.0;
+  coord cy = 0.0;
+  
+  real width = 0.0;
+  real height = 0.0;
+  
+  real xoffs = custom->xoffs;
+  real yoffs = custom->yoffs;
+  
+  /* step 1: calculate boundaries */
+  Rectangle orig_bounds = custom->info->shape_bounds;
+  Rectangle new_bounds;
+  
+  /* step 2: undo unkown/funky number magic when flip_h or flip_v is set */
+  if(custom->flip_h) custom->xscale = -custom->xscale;
+  if(custom->flip_v) custom->yscale = -custom->yscale;
+  
+  new_bounds.top = orig_bounds.top * custom->yscale;
+  new_bounds.bottom = orig_bounds.bottom * custom->yscale;
+  new_bounds.left = orig_bounds.left * custom->xscale;
+  new_bounds.right = orig_bounds.right * custom->xscale;
+
+  width = new_bounds.right - new_bounds.left;
+  height = new_bounds.bottom - new_bounds.top;
+
+  /* step #3: calculate the new center */
+  if (subshape->h_anchor_method == OFFSET_METHOD_PROPORTIONAL) {
+    /* handle proportional offset in x direction */
+    cx = subshape->center.x * custom->xscale;
+  } else {
+    /* handle fixed offset in x direction */
+    if (subshape->h_anchor_method < 0) {
+      cx = new_bounds.right - ((orig_bounds.right-subshape->center.x) * scale);
+    } else {
+      cx = new_bounds.left + (subshape->center.x * scale);
+    }
+  }
+    
+  if (subshape->v_anchor_method == OFFSET_METHOD_PROPORTIONAL) {
+    /* handle proportional offset in y direction */
+    cy = subshape->center.y * custom->yscale;
+  } else {
+    /* handle fixed offset in y direction */
+    if (subshape->v_anchor_method < 0) {
+      cy = new_bounds.bottom - ((orig_bounds.bottom-subshape->center.y) * scale);
+    } else {
+      cy = new_bounds.top + (subshape->center.y * scale);
+   }
+  }
+  
+  /* step #4: calculate the new coordinate relative to the calculated center */
+  out->x = cx - ((subshape->center.x - p1->x) * scale);
+  out->y = cy - ((subshape->center.y - p1->y) * scale);
+  
+  /* step #5: handle flip_h/flip_v */
+  if (custom->flip_h) {
+    out->x = -out->x + width;
+    cx = -cx + width;
+    
+    xoffs -= (new_bounds.right - new_bounds.left);
+    custom->xscale = -custom->xscale; /* undo the damage we've done above */
+  }
+  if (custom->flip_v) {
+    out->y = -out->y + height;
+    cy = -cy + height;
+  
+    yoffs -= (new_bounds.bottom - new_bounds.top);
+    custom->yscale = -custom->yscale; /* undo the damage we've done above */
+  }
+  
+  /* step #6: finally, translate the coordinate to the correct offset */
+  out->x += xoffs;
+  out->y += yoffs;
+}
 
 static void
 transform_coord(Custom *custom, const Point *p1, Point *out)
 {
-  out->x = p1->x * custom->xscale + custom->xoffs;
-  out->y = p1->y * custom->yscale + custom->yoffs;
+  if (custom->current_subshape != NULL) {
+    transform_subshape_coord(custom, custom->current_subshape, p1, out);
+  } else {
+    out->x = p1->x * custom->xscale + custom->xoffs;
+    out->y = p1->y * custom->yscale + custom->yoffs;
+  }
 }
 
 static void
@@ -558,6 +677,58 @@
   element_update_handles(&custom->element);
 }
 
+static void
+custom_adjust_scale(Custom *custom, Handle *handle,
+		   Point *to, ConnectionPoint *cp,
+		   HandleMoveReason reason, ModifierKeys modifiers)
+{
+#define IS_MODIFIER_PRESSED(m) ((modifiers&(m)) != 0)
+  
+  static int uniform_scale = FALSE;
+  static Point orig_pos;
+
+  float delta_max = 0.0f;
+
+  switch (reason) {
+  case HANDLE_MOVE_USER:
+    if (!uniform_scale) {
+      orig_pos.x = to->x;
+      orig_pos.y = to->y;
+    }
+    
+    if (!uniform_scale && IS_MODIFIER_PRESSED(MODIFIER_SHIFT)) {
+      custom->old_subscale = MAX(custom->subscale, 0.0);
+    }
+    
+    uniform_scale = IS_MODIFIER_PRESSED(MODIFIER_SHIFT);
+
+    delta_max = (to->x - orig_pos.x);
+    
+#ifdef USE_DELTA_MAX
+    /* This may yield some awkard effects for new-comers.
+     * Maybe we should make it a configurable option.
+     */
+    if (ABS(to->y - orig_pos.y) > ABS(delta_max))
+    	delta_max = (to->y - orig_pos.y);
+#endif
+    
+    if (uniform_scale)
+      custom->subscale =
+        custom->old_subscale + (SUBSCALE_ACCELERATION * delta_max);
+
+    if( custom->subscale < SUBSCALE_MININUM_SCALE )
+      custom->subscale = SUBSCALE_MININUM_SCALE;
+
+#undef IS_MODIFIER_PRESSED
+    break;
+  case HANDLE_MOVE_USER_FINAL:
+    uniform_scale = FALSE;
+    break;
+  default:
+    break;
+  } 
+}
+
 static ObjectChange*
 custom_move_handle(Custom *custom, Handle *handle,
 		   Point *to, ConnectionPoint *cp,
@@ -569,6 +740,12 @@
   assert(handle!=NULL);
   assert(to!=NULL);
 
+  switch (reason) {
+  case HANDLE_MOVE_USER:
+  case HANDLE_MOVE_USER_FINAL:
+    custom_adjust_scale(custom, handle, to, cp, reason, modifiers);
+  }
+  
   element_move_handle(&custom->element, handle->id, to, cp, reason, modifiers);
 
   switch (handle->id) {
@@ -634,11 +811,6 @@
 {
   DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
   static GArray *arr = NULL, *barr = NULL;
-  Point p1, p2;
-  real coord;
-  int i;
-  GList *tmp;
-  Element *elem;
   real cur_line = 1.0, cur_dash = 1.0;
   LineCaps cur_caps = LINECAPS_BUTT;
   LineJoin cur_join = LINEJOIN_MITER;
@@ -652,8 +824,6 @@
   if (!barr)
     barr = g_array_new(FALSE, FALSE, sizeof(BezPoint));
 
-  elem = &custom->element;
-
   renderer_ops->set_fillstyle(renderer, FILLSTYLE_SOLID);
   renderer_ops->set_linewidth(renderer, custom->border_width);
   cur_line = custom->border_width;
@@ -662,173 +832,301 @@
   renderer_ops->set_linecaps(renderer, cur_caps);
   renderer_ops->set_linejoin(renderer, cur_join);
 
-  for (tmp = custom->info->display_list; tmp; tmp = tmp->next) {
+  /* 
+   * Because we do not know if any of these values are reused in the loop, we pass
+   * them all by reference.
+   * If anyone does know this, please correct/simplify.
+   */
+  custom_draw_displaylist(custom->info->display_list, custom, renderer, arr, barr,
+                          &cur_line, &cur_dash, &cur_caps, &cur_join, &cur_style);
+
+  if (custom->info->has_text) {
+    /*Rectangle tb;
+    
+    if (renderer->is_interactive) {
+    transform_rect(custom, &custom->info->text_bounds, &tb);
+    p1.x = tb.left;  p1.y = tb.top;
+    p2.x = tb.right; p2.y = tb.bottom;
+    renderer_ops->draw_rect(renderer, &p1, &p2, &custom->border_color);
+    }*/
+    text_draw(custom->text, renderer);
+  }
+}
+
+static void
+custom_draw_displaylist(GList *display_list, Custom *custom, DiaRenderer *renderer,
+                        GArray *arr, GArray *barr, real* cur_line, real* cur_dash,
+                        LineCaps* cur_caps, LineJoin* cur_join, LineStyle* cur_style)
+{
+  GList *tmp;
+  for (tmp = display_list; tmp; tmp = tmp->next) {
     GraphicElement *el = tmp->data;
     Color fg, bg;
 
-    if (el->any.s.line_width != cur_line) {
-      cur_line = el->any.s.line_width;
-      renderer_ops->set_linewidth(renderer,
-				  custom->border_width*cur_line);
-    }
-    if ((el->any.s.linecap == DIA_SVG_LINECAPS_DEFAULT && cur_caps != LINECAPS_BUTT) ||
-	el->any.s.linecap != cur_caps) {
-      cur_caps = (el->any.s.linecap!=DIA_SVG_LINECAPS_DEFAULT) ?
-	el->any.s.linecap : LINECAPS_BUTT;
-      renderer_ops->set_linecaps(renderer, cur_caps);
-    }
-    if ((el->any.s.linejoin==DIA_SVG_LINEJOIN_DEFAULT && cur_join!=LINEJOIN_MITER) ||
-	el->any.s.linejoin != cur_join) {
-      cur_join = (el->any.s.linejoin!=DIA_SVG_LINEJOIN_DEFAULT) ?
-	el->any.s.linejoin : LINEJOIN_MITER;
-      renderer_ops->set_linejoin(renderer, cur_join);
-    }
-    if ((el->any.s.linestyle == DIA_SVG_LINESTYLE_DEFAULT &&
-	 cur_style != custom->line_style) ||
-	el->any.s.linestyle != cur_style) {
-      cur_style = (el->any.s.linestyle!=DIA_SVG_LINESTYLE_DEFAULT) ?
-	el->any.s.linestyle : custom->line_style;
-      renderer_ops->set_linestyle(renderer, cur_style);
-    }
-    if (el->any.s.dashlength != cur_dash) {
-      cur_dash = el->any.s.dashlength;
-      renderer_ops->set_dashlength(renderer,
-				   custom->dashlength*cur_dash);
-    }
+    /* 
+     * Because we do not know if any of these values are reused in the loop, 
+     * we pass them all by reference.
+     * If anyone does know this, please correct/simplify.
+     */
+    custom_draw_element( el, custom, renderer, arr, barr, cur_line, cur_dash,
+                         cur_caps, cur_join, cur_style, &fg, &bg );
+  }
+}
+
+static void
+custom_draw_element(GraphicElement* el, Custom *custom, DiaRenderer *renderer, 
+                    GArray *arr, GArray *barr, real* cur_line, real* cur_dash,
+                    LineCaps* cur_caps, LineJoin* cur_join, LineStyle* cur_style,
+                    Color* fg, Color* bg)
+{
+  DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
+  Point p1, p2;
+  real coord;
+  int i;
+    
+  if (el->any.s.line_width != (*cur_line)) {
+    (*cur_line) = el->any.s.line_width;
+    renderer_ops->set_linewidth(renderer,
+		  custom->border_width*(*cur_line));
+  }
+  if ((el->any.s.linecap == DIA_SVG_LINECAPS_DEFAULT && (*cur_caps) != LINECAPS_BUTT) ||
+    el->any.s.linecap != (*cur_caps)) {
+      (*cur_caps) = (el->any.s.linecap!=DIA_SVG_LINECAPS_DEFAULT) ?
+      el->any.s.linecap : LINECAPS_BUTT;
+      renderer_ops->set_linecaps(renderer, (*cur_caps));
+    }
+  if ((el->any.s.linejoin==DIA_SVG_LINEJOIN_DEFAULT && (*cur_join)!=LINEJOIN_MITER) ||
+      el->any.s.linejoin != (*cur_join)) {
+    (*cur_join) = (el->any.s.linejoin!=DIA_SVG_LINEJOIN_DEFAULT) ?
+    el->any.s.linejoin : LINEJOIN_MITER;
+    renderer_ops->set_linejoin(renderer, (*cur_join));
+  }
+  if ((el->any.s.linestyle == DIA_SVG_LINESTYLE_DEFAULT &&
+      (*cur_style) != custom->line_style) || el->any.s.linestyle != (*cur_style)) {
+    (*cur_style) = (el->any.s.linestyle!=DIA_SVG_LINESTYLE_DEFAULT) ?
+    el->any.s.linestyle : custom->line_style;
+    renderer_ops->set_linestyle(renderer, (*cur_style));
+  }
+  if (el->any.s.dashlength != (*cur_dash)) {
+    (*cur_dash) = el->any.s.dashlength;
+    renderer_ops->set_dashlength(renderer,
+		   custom->dashlength*(*cur_dash));
+  }
       
-    cur_line = el->any.s.line_width;
-    get_colour(custom, &fg, el->any.s.stroke);
-    get_colour(custom, &bg, el->any.s.fill);
-    switch (el->type) {
-    case GE_LINE:
-      transform_coord(custom, &el->line.p1, &p1);
-      transform_coord(custom, &el->line.p2, &p2);
-      if (el->any.s.stroke != DIA_SVG_COLOUR_NONE)
-	renderer_ops->draw_line(renderer, &p1, &p2, &fg);
-      break;
-    case GE_POLYLINE:
-      g_array_set_size(arr, el->polyline.npoints);
-      for (i = 0; i < el->polyline.npoints; i++)
-	transform_coord(custom, &el->polyline.points[i],
+  (*cur_line) = el->any.s.line_width;
+  get_colour(custom, fg, el->any.s.stroke);
+  get_colour(custom, bg, el->any.s.fill);
+  switch (el->type) {
+  case GE_LINE:
+    transform_coord(custom, &el->line.p1, &p1);
+    transform_coord(custom, &el->line.p2, &p2);
+    if (el->any.s.stroke != DIA_SVG_COLOUR_NONE)
+      renderer_ops->draw_line(renderer, &p1, &p2, fg);
+    break;
+  case GE_POLYLINE:
+    g_array_set_size(arr, el->polyline.npoints);
+    for (i = 0; i < el->polyline.npoints; i++)
+      transform_coord(custom, &el->polyline.points[i],
 			&g_array_index(arr, Point, i));
-      if (el->any.s.stroke != DIA_SVG_COLOUR_NONE)
-	renderer_ops->draw_polyline(renderer,
-				    (Point *)arr->data, el->polyline.npoints,
-				    &fg);
-      break;
-    case GE_POLYGON:
-      g_array_set_size(arr, el->polygon.npoints);
-      for (i = 0; i < el->polygon.npoints; i++)
-	transform_coord(custom, &el->polygon.points[i],
+    if (el->any.s.stroke != DIA_SVG_COLOUR_NONE)
+      renderer_ops->draw_polyline(renderer,
+              (Point *)arr->data, el->polyline.npoints,
+				    fg);
+    break;
+  case GE_POLYGON:
+    g_array_set_size(arr, el->polygon.npoints);
+    for (i = 0; i < el->polygon.npoints; i++)
+      transform_coord(custom, &el->polygon.points[i],
 			&g_array_index(arr, Point, i));
-      if (custom->show_background && el->any.s.fill != DIA_SVG_COLOUR_NONE) 
-	renderer_ops->fill_polygon(renderer,
+    if (custom->show_background && el->any.s.fill != DIA_SVG_COLOUR_NONE) 
+      renderer_ops->fill_polygon(renderer,
 				   (Point *)arr->data, el->polygon.npoints,
-				   &bg);
-      if (el->any.s.stroke != DIA_SVG_COLOUR_NONE)
-	renderer_ops->draw_polygon(renderer,
+				   bg);
+    if (el->any.s.stroke != DIA_SVG_COLOUR_NONE)
+      renderer_ops->draw_polygon(renderer,
 				   (Point *)arr->data, el->polygon.npoints,
-				   &fg);
-      break;
-    case GE_RECT:
-      transform_coord(custom, &el->rect.corner1, &p1);
-      transform_coord(custom, &el->rect.corner2, &p2);
-      if (p1.x > p2.x) {
-	coord = p1.x;
-	p1.x = p2.x;
-	p2.x = coord;
-      }
-      if (p1.y > p2.y) {
-	coord = p1.y;
-	p1.y = p2.y;
-	p2.y = coord;
-      }
-      if (custom->show_background && el->any.s.fill != DIA_SVG_COLOUR_NONE)
-	renderer_ops->fill_rect(renderer, &p1, &p2, &bg);
-      if (el->any.s.stroke != DIA_SVG_COLOUR_NONE)
-	renderer_ops->draw_rect(renderer, &p1, &p2, &fg);
-      break;
-    case GE_TEXT:
-      custom_reposition_text(custom, &el->text);
-      text_draw(el->text.object, renderer);
-      text_set_position(el->text.object, &el->text.anchor);
-      break;
-    case GE_ELLIPSE:
-      transform_coord(custom, &el->ellipse.center, &p1);
-      if (custom->show_background && el->any.s.fill != DIA_SVG_COLOUR_NONE)
-	renderer_ops->fill_ellipse(renderer, &p1,
+				   fg);
+    break;
+  case GE_RECT:
+    transform_coord(custom, &el->rect.corner1, &p1);
+    transform_coord(custom, &el->rect.corner2, &p2);
+    if (p1.x > p2.x) {
+      coord = p1.x;
+	  p1.x = p2.x;
+	  p2.x = coord;
+    }
+    if (p1.y > p2.y) {
+      coord = p1.y;
+      p1.y = p2.y;
+      p2.y = coord;
+    }
+    if (custom->show_background && el->any.s.fill != DIA_SVG_COLOUR_NONE)
+      renderer_ops->fill_rect(renderer, &p1, &p2, bg);
+    if (el->any.s.stroke != DIA_SVG_COLOUR_NONE)
+      renderer_ops->draw_rect(renderer, &p1, &p2, fg);
+    break;
+  case GE_TEXT:
+    custom_reposition_text(custom, &el->text);
+    text_draw(el->text.object, renderer);
+    text_set_position(el->text.object, &el->text.anchor);
+    break;
+  case GE_ELLIPSE:
+    transform_coord(custom, &el->ellipse.center, &p1);
+    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);
-      if (el->any.s.stroke != DIA_SVG_COLOUR_NONE)
-	renderer_ops->draw_ellipse(renderer, &p1,
+				   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);
-      break;
-    case GE_IMAGE:
-      transform_coord(custom, &el->image.topleft, &p1);
-      renderer_ops->draw_image(renderer, &p1,
+				   fg);
+    break;
+  case GE_IMAGE:
+    transform_coord(custom, &el->image.topleft, &p1);
+    renderer_ops->draw_image(renderer, &p1,
 			       el->image.width * fabs(custom->xscale),
 			       el->image.height * fabs(custom->yscale),
 			       el->image.image);
-      break;
-    case GE_PATH:
-      g_array_set_size(barr, el->path.npoints);
-      for (i = 0; i < el->path.npoints; i++)
-	switch (g_array_index(barr,BezPoint,i).type=el->path.points[i].type) {
-	case BEZ_CURVE_TO:
-	  transform_coord(custom, &el->path.points[i].p3,
-			  &g_array_index(barr, BezPoint, i).p3);
-	  transform_coord(custom, &el->path.points[i].p2,
-			  &g_array_index(barr, BezPoint, i).p2);
-	case BEZ_MOVE_TO:
-	case BEZ_LINE_TO:
-	  transform_coord(custom, &el->path.points[i].p1,
-			  &g_array_index(barr, BezPoint, i).p1);
-	}
-      if (el->any.s.stroke != DIA_SVG_COLOUR_NONE)
-	renderer_ops->draw_bezier(renderer, (BezPoint *)barr->data,
-				  el->path.npoints, &fg);
-      break;
-    case GE_SHAPE:
-      g_array_set_size(barr, el->path.npoints);
-      for (i = 0; i < el->path.npoints; i++)
-	switch (g_array_index(barr,BezPoint,i).type=el->path.points[i].type) {
-	case BEZ_CURVE_TO:
-	  transform_coord(custom, &el->path.points[i].p3,
+    break;
+  case GE_PATH:
+    g_array_set_size(barr, el->path.npoints);
+    for (i = 0; i < el->path.npoints; i++)
+      switch (g_array_index(barr,BezPoint,i).type=el->path.points[i].type) {
+        case BEZ_CURVE_TO:
+            transform_coord(custom, &el->path.points[i].p3,
+              &g_array_index(barr, BezPoint, i).p3);
+            transform_coord(custom, &el->path.points[i].p2,
+              &g_array_index(barr, BezPoint, i).p2);
+        case BEZ_MOVE_TO:
+        case BEZ_LINE_TO:
+          transform_coord(custom, &el->path.points[i].p1,
+            &g_array_index(barr, BezPoint, i).p1);
+    }
+    if (el->any.s.stroke != DIA_SVG_COLOUR_NONE)
+      renderer_ops->draw_bezier(renderer, (BezPoint *)barr->data,
+				  el->path.npoints, fg);
+    break;
+  case GE_SHAPE:
+    g_array_set_size(barr, el->path.npoints);
+    for (i = 0; i < el->path.npoints; i++)
+      switch (g_array_index(barr,BezPoint,i).type=el->path.points[i].type) {
+        case BEZ_CURVE_TO:
+          transform_coord(custom, &el->path.points[i].p3,
 			  &g_array_index(barr, BezPoint, i).p3);
-	  transform_coord(custom, &el->path.points[i].p2,
+          transform_coord(custom, &el->path.points[i].p2,
 			  &g_array_index(barr, BezPoint, i).p2);
-	case BEZ_MOVE_TO:
-	case BEZ_LINE_TO:
-	  transform_coord(custom, &el->path.points[i].p1,
-			  &g_array_index(barr, BezPoint, i).p1);
-	}
-      if (custom->show_background && el->any.s.fill != DIA_SVG_COLOUR_NONE)
-	renderer_ops->fill_bezier(renderer, (BezPoint *)barr->data,
-				  el->path.npoints, &bg);
-      if (el->any.s.stroke != DIA_SVG_COLOUR_NONE)
-	renderer_ops->draw_bezier(renderer, (BezPoint *)barr->data,
-				  el->path.npoints, &fg);
-      break;
+        case BEZ_MOVE_TO:
+        case BEZ_LINE_TO:
+          transform_coord(custom, &el->path.points[i].p1,
+              &g_array_index(barr, BezPoint, i).p1);
     }
+    if (custom->show_background && el->any.s.fill != DIA_SVG_COLOUR_NONE)
+      renderer_ops->fill_bezier(renderer, (BezPoint *)barr->data,
+				  el->path.npoints, bg);
+    if (el->any.s.stroke != DIA_SVG_COLOUR_NONE)
+      renderer_ops->draw_bezier(renderer, (BezPoint *)barr->data,
+				  el->path.npoints, fg);
+    break;
+  case GE_SUBSHAPE:
+    {
+      GraphicElementSubShape* subshape = (GraphicElementSubShape*)el;
+      
+      custom->current_subshape = subshape;
+      custom_draw_displaylist(subshape->display_list, custom, renderer, arr, barr, cur_line, cur_dash, cur_caps, cur_join, cur_style);
+      custom->current_subshape = NULL;
+    }
+    break;
   }
+}
 
-  if (custom->info->has_text) {
-    /*Rectangle tb;
+static void
+assert_boundaries(Custom *custom)
+{
+  Element *elem = &custom->element;
+  ShapeInfo *info = custom->info;
+  
+  int i = 0;
+  GList *tmp;
+  
+  real min_width = 0.0;
+  real min_height = 0.0;
+  real r = 0.0;
+
+  /* undo unkown/funky number magic when flip_h or flip_v is set */
+  if (custom->flip_h) custom->xscale = -custom->xscale;
+  if (custom->flip_v) custom->yscale = -custom->yscale;
+ 
+  /* calculate the minimum width and height required for all subshapes */
+  for (tmp = info->subshapes; tmp != NULL; tmp = tmp->next, i++) {
+    GraphicElementSubShape *subshape = tmp->data;
     
-    if (renderer->is_interactive) {
-    transform_rect(custom, &custom->info->text_bounds, &tb);
-    p1.x = tb.left;  p1.y = tb.top;
-    p2.x = tb.right; p2.y = tb.bottom;
-    renderer_ops->draw_rect(renderer, &p1, &p2, &custom->border_color);
-    }*/
-    text_draw(custom->text, renderer);
+    real parent_shape_orig_width = info->shape_bounds.right - info->shape_bounds.left;
+    real parent_shape_orig_height = info->shape_bounds.bottom - info->shape_bounds.top;
+    
+    real scale = custom->subscale * subshape->default_scale;
+    real width = (2*subshape->half_width) * scale;
+    real height = (2*subshape->half_height) * scale;
+
+    if (subshape->h_anchor_method == OFFSET_METHOD_PROPORTIONAL) {
+      /* handle proportional anchor in x direction */
+      real prop_min_width = subshape->center.x / parent_shape_orig_width;
+      real scaled_half_width = subshape->half_width * scale;
+
+      if (prop_min_width > 0.5)
+        prop_min_width = 1.0 - prop_min_width;
+        
+      r = prop_min_width * parent_shape_orig_width*custom->xscale;
+        
+      if (scaled_half_width > r)
+        width = (scaled_half_width / prop_min_width)-0.01;
+    
+    } else {
+      /* handle fixed anchor in x direction */
+      if (subshape->h_anchor_method > 0)
+        width = (subshape->center.x + subshape->half_width) * scale;
+      else
+        width = (parent_shape_orig_width - subshape->center.x + subshape->half_width) * scale;
+    }
+
+    if (subshape->v_anchor_method == OFFSET_METHOD_PROPORTIONAL) {
+      /* handle proportional anchor in y direction */
+      real prop_min_height = subshape->center.y / parent_shape_orig_height;
+      real scaled_half_height = subshape->half_height * scale;
+        
+      if (prop_min_height > 0.5)
+        prop_min_height = 1.0 - prop_min_height;
+      
+      r = prop_min_height * parent_shape_orig_height*custom->yscale;
+      	
+      if (scaled_half_height > r)
+        height = (scaled_half_height / prop_min_height)-0.01;
+      
+    } else {
+      /* handle fixed anchor in y direction */
+      if (subshape->v_anchor_method > 0)
+        height = (subshape->center.y + subshape->half_height) * scale;
+      else if(subshape->v_anchor_method < 0)
+        height = (parent_shape_orig_height - subshape->center.y + subshape->half_height) * scale;
+    }
+
+    if (width > min_width)
+      min_width = width;
+    if (height > min_height)
+      min_height = height;
   }
+  
+  if (elem->width < min_width)
+    elem->width = min_width;
+  if (elem->height < min_height)
+    elem->height = min_height;
+  
+  /* redo unkown/funky number magic when flip_h or flip_v is set */
+  if (custom->flip_h) custom->xscale = -custom->xscale;
+  if (custom->flip_v) custom->yscale = -custom->yscale;
 }
 
-
 static void
 custom_update_data(Custom *custom, AnchorShape horiz, AnchorShape vert)
 {
@@ -849,7 +1147,9 @@
   bottom_right.x += elem->width;
   center.y += elem->height/2;
   bottom_right.y += elem->height;
-
+  
+  assert_boundaries(custom);
+  
   /* update the translation coefficients first ... */
   custom->xscale = elem->width / (info->shape_bounds.right -
 				  info->shape_bounds.left);
@@ -1233,10 +1533,17 @@
   obj->ops = &custom_ops;
 
   elem->corner = *startpoint;
-  elem->width = DEFAULT_WIDTH;
-  elem->height = DEFAULT_HEIGHT;
+
+  elem->width = shape_info_get_default_width(info) / 
+                         units[prefs_get_length_unit()].factor;
+  elem->height = shape_info_get_default_height(info) /
+                         units[prefs_get_length_unit()].factor;
 
   custom->info = info;
+  
+  custom->old_subscale = 1.0;
+  custom->subscale = 1.0;
+  custom->current_subshape = NULL;
 
   custom->border_width =  attributes_get_default_linewidth();
   custom->border_color = attributes_get_foreground();
@@ -1329,6 +1636,10 @@
   newcustom->flip_h = custom->flip_h;
   newcustom->flip_v = custom->flip_v;
 
+  newcustom->current_subshape = custom->current_subshape;
+  newcustom->old_subscale = custom->old_subscale;
+  newcustom->subscale = custom->subscale;
+
   if (custom->info->has_text) {
     newcustom->text = text_copy(custom->text);
     text_get_attributes(newcustom->text,&newcustom->attrs);
@@ -1368,6 +1679,7 @@
     object_load_props(obj,obj_node);
   
     custom_update_data(custom, ANCHOR_MIDDLE, ANCHOR_MIDDLE);
+    custom->old_subscale = custom->subscale;
   }
   return obj;
 }

Modified: trunk/objects/custom/shape_info.c
==============================================================================
--- trunk/objects/custom/shape_info.c	(original)
+++ trunk/objects/custom/shape_info.c	Tue Feb 12 17:15:00 2008
@@ -4,6 +4,9 @@
  * Custom Objects -- objects defined in XML rather than C.
  * Copyright (C) 1999 James Henstridge.
  *
+ * Non-uniform scaling/subshape support by Marcel Toele.
+ * Modifications (C) 2007 Kern Automatiseringsdiensten BV.
+ *
  * 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
@@ -34,10 +37,13 @@
 #include "message.h"
 #include "intl.h"
 
+#include "units.h"
+
 #define FONT_HEIGHT_DEFAULT 1
 #define TEXT_ALIGNMENT_DEFAULT ALIGN_CENTER
 
 static ShapeInfo *load_shape_info(const gchar *filename, ShapeInfo *preload);
+static void update_bounds(ShapeInfo *info);
 
 static GHashTable *name_to_info = NULL;
 
@@ -122,6 +128,23 @@
   }  
 }
 
+real
+shape_info_get_default_width(ShapeInfo *info)
+{
+  if (info->default_width == 0.0)
+    info->default_width = DEFAULT_WIDTH * units[prefs_get_length_unit()].factor;
+  
+  return( info->default_width );
+}
+
+real
+shape_info_get_default_height(ShapeInfo *info)
+{
+  if (info->default_height == 0.0)
+    info->default_height = DEFAULT_HEIGHT * units[prefs_get_length_unit()].factor;
+  
+  return( info->default_height );
+}
 
 static void
 parse_path(ShapeInfo *info, const char *path_str, DiaSvgStyle *s, const char* filename)
@@ -166,6 +189,23 @@
   g_array_free (points, TRUE);
 }
 
+static gboolean
+is_subshape(xmlElement* elt)
+{
+  gboolean res = FALSE;
+
+  if (xmlHasProp(elt, "subshape")) {
+    gchar* value = xmlGetProp(elt, "subshape");
+    
+    if (!strcmp(value, "true"))
+      res = TRUE;
+    
+    xmlFree(value);
+  }
+
+  return res;
+}
+
 static void
 parse_svg_node(ShapeInfo *info, xmlNodePtr node, xmlNsPtr svg_ns,
                DiaSvgStyle *style, const gchar *filename)
@@ -412,8 +452,72 @@
         xmlFree(str);
       }
     } else if (!xmlStrcmp(node->name, (const xmlChar *)"g")) {
+      if (!is_subshape((xmlElement*)node)) {
           /* add elements from the group element */
-      parse_svg_node(info, node, svg_ns, &s, filename);
+        parse_svg_node(info, node, svg_ns, &s, filename);
+      } else {
+          /* add elements from the group element, but make it a subshape */
+        GraphicElementSubShape *subshape = g_new0(GraphicElementSubShape, 1);
+        ShapeInfo* tmpinfo = g_new0(ShapeInfo, 1);
+        DiaSvgStyle tmp_s = {
+                1.0, DIA_SVG_COLOUR_FOREGROUND, 
+                DIA_SVG_COLOUR_NONE,
+                DIA_SVG_LINECAPS_DEFAULT, 
+                DIA_SVG_LINEJOIN_DEFAULT,
+                DIA_SVG_LINESTYLE_DEFAULT, 1.0
+        };
+        xmlAttrPtr v_anchor_attr = xmlGetProp(node,"v_anchor");
+        xmlAttrPtr h_anchor_attr = xmlGetProp(node,"h_anchor");
+      
+        parse_svg_node(tmpinfo, node, svg_ns, &tmp_s, filename);
+        
+        tmpinfo->shape_bounds.top = DBL_MAX;
+        tmpinfo->shape_bounds.left = DBL_MAX;
+        tmpinfo->shape_bounds.bottom = -DBL_MAX;
+        tmpinfo->shape_bounds.right = -DBL_MAX;
+
+        update_bounds( tmpinfo );
+        update_bounds( info );
+        
+        subshape->half_width = (tmpinfo->shape_bounds.right-tmpinfo->shape_bounds.left) / 2.0;
+        subshape->half_height = (tmpinfo->shape_bounds.bottom-tmpinfo->shape_bounds.top) / 2.0;
+        subshape->center.x = tmpinfo->shape_bounds.left + subshape->half_width;
+        subshape->center.y = tmpinfo->shape_bounds.top + subshape->half_height;
+            
+        subshape->type = GE_SUBSHAPE;
+        subshape->display_list = tmpinfo->display_list;
+        subshape->v_anchor_method = OFFSET_METHOD_FIXED;
+        subshape->h_anchor_method = OFFSET_METHOD_FIXED;
+        subshape->default_scale = 0.0;
+                
+        if (!v_anchor_attr || !strcmp(v_anchor_attr,"fixed.top"))
+          subshape->v_anchor_method = OFFSET_METHOD_FIXED;
+        else if (v_anchor_attr && !strcmp(v_anchor_attr,"fixed.bottom"))
+          subshape->v_anchor_method = -OFFSET_METHOD_FIXED;
+        else if (v_anchor_attr && !strcmp(v_anchor_attr,"proportional"))
+          subshape->v_anchor_method = OFFSET_METHOD_PROPORTIONAL;
+        else
+          fprintf( stderr, "illegal v_anchor `%s', defaulting to fixed.top\n",
+                   v_anchor_attr );
+          
+        if (!h_anchor_attr || !strcmp(h_anchor_attr,"fixed.left"))
+          subshape->h_anchor_method = OFFSET_METHOD_FIXED;
+        else if (h_anchor_attr && !strcmp(h_anchor_attr,"fixed.right"))
+          subshape->h_anchor_method = -OFFSET_METHOD_FIXED;
+        else if (h_anchor_attr && !strcmp(h_anchor_attr,"proportional"))
+          subshape->h_anchor_method = OFFSET_METHOD_PROPORTIONAL;
+        else
+          fprintf( stderr, "illegal h_anchor `%s', defaulting to fixed.left\n",
+                   h_anchor_attr );
+        
+        info->subshapes = g_list_append(info->subshapes, subshape);
+        
+        /* gfree( tmpinfo );*/
+        xmlFree(v_anchor_attr);
+        xmlFree(h_anchor_attr);
+        
+        el = (GraphicElementSubShape *)subshape;
+      }    
     }
     if (el) {
       el->any.s = s;
@@ -497,6 +601,17 @@
       break;
     }
   }
+  
+  {
+    real width = info->shape_bounds.right-info->shape_bounds.left;
+    real height = info->shape_bounds.bottom-info->shape_bounds.top;
+    
+    if (info->default_width > 0.0 && info->default_height == 0.0) {
+      info->default_height = (info->default_width / width) * height;
+    } else if (info->default_height > 0.0 && info->default_width == 0.0) {
+      info->default_width = (info->default_height / height) * width;      
+    }
+  }
 }
 
 static ShapeInfo *
@@ -546,6 +661,8 @@
   info->shape_bounds.bottom = -DBL_MAX;
   info->shape_bounds.right = -DBL_MAX;
   info->aspect_type = SHAPE_ASPECT_FREE; 
+  info->default_width = 0.0;
+  info->default_height = 0.0;
   info->main_cp = -1;
 
   i = 0;
@@ -556,7 +673,7 @@
       tmp = (gchar *) xmlNodeGetContent(node);
       if (preload) { 
         if (strcmp (tmp, info->name) != 0)
-          g_warning ("Shape(preoad) '%s' can't change name '%s'", info->name, tmp);
+          g_warning ("Shape(preload) '%s' can't change name '%s'", info->name, tmp);
         /* the key name is already used as key in name_to_info */
       } else {
         g_free(info->name);
@@ -680,6 +797,35 @@
 	}
 	xmlFree(tmp);
       }
+    } else if (node->ns == shape_ns && (!xmlStrcmp(node->name, (const xmlChar *)"default-width") || !xmlStrcmp(node->name, (const xmlChar *)"default-height"))) {
+      
+      int j = 0;
+      DiaUnitDef ud;
+      
+      gdouble val = 0.0;
+      
+      int unit_ssize = 0;
+      int ssize = 0;
+      tmp = (gchar *) xmlNodeGetContent(node);
+      ssize = strlen(tmp);
+
+      val = g_ascii_strtod(tmp, NULL);
+
+      for (j = 0, ud = units[i]; ud.name; ud = units[++j]) {
+        unit_ssize = strlen(ud.unit);
+        if (ssize > unit_ssize && !strcmp(tmp+(ssize-unit_ssize), ud.unit)) {
+          val *= ud.factor;
+          break;
+        }
+      }
+
+      if (!xmlStrcmp(node->name, (const xmlChar *)"default-width")) {
+        info->default_width = val;
+      } else {
+        info->default_height = val;
+      }
+      
+      xmlFree(tmp);
     } else if (node->ns == svg_ns && !xmlStrcmp(node->name, (const xmlChar *)"svg")) {
       DiaSvgStyle s = {
 	1.0, DIA_SVG_COLOUR_FOREGROUND, DIA_SVG_COLOUR_NONE,

Modified: trunk/objects/custom/shape_info.h
==============================================================================
--- trunk/objects/custom/shape_info.h	(original)
+++ trunk/objects/custom/shape_info.h	Tue Feb 12 17:15:00 2008
@@ -4,6 +4,9 @@
  * Custom Objects -- objects defined in XML rather than C.
  * Copyright (C) 1999 James Henstridge.
  *
+ * Non-uniform scaling/subshape support by Marcel Toele.
+ * Modifications (C) 2007 Kern Automatiseringsdiensten BV.
+ *
  * 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
@@ -39,7 +42,8 @@
   GE_PATH,
   GE_SHAPE,
   GE_TEXT,
-  GE_IMAGE
+  GE_IMAGE,
+  GE_SUBSHAPE
 } GraphicElementType;
 
 typedef union _GraphicElement GraphicElement;
@@ -51,6 +55,7 @@
 typedef struct _GraphicElementPath GraphicElementPath;
 typedef struct _GraphicElementText GraphicElementText;
 typedef struct _GraphicElementImage GraphicElementImage;
+typedef struct _GraphicElementSubShape GraphicElementSubShape;
 
 #define SHAPE_INFO_COMMON  \
   GraphicElementType type; \
@@ -103,6 +108,26 @@
   DiaImage image;
 };
 
+#define OFFSET_METHOD_PROPORTIONAL 0
+#define OFFSET_METHOD_FIXED   1
+#define SUBSCALE_ACCELERATION 1
+#define SUBSCALE_MININUM_SCALE 0.0001
+struct _GraphicElementSubShape {
+  SHAPE_INFO_COMMON;
+  GList *display_list;
+  
+  gint h_anchor_method;
+  gint v_anchor_method;
+  
+  real default_scale;
+  
+  /* subshape bounding box, center, ... */
+  
+  Point center;
+  real half_width;
+  real half_height;
+};
+
 #undef SHAPE_INFO_COMMON
 
 union _GraphicElement {
@@ -117,6 +142,7 @@
   GraphicElementPath shape;
   GraphicElementText text;
   GraphicElementImage image;
+  GraphicElementSubShape subshape;
 };
 
 typedef struct _ExtAttribute {
@@ -131,6 +157,10 @@
   SHAPE_ASPECT_RANGE
 } ShapeAspectType;
 
+#define DEFAULT_WIDTH 2.0
+#define DEFAULT_HEIGHT 2.0
+#define DEFAULT_BORDER 0.25
+
 typedef struct _ShapeInfo ShapeInfo;
 struct _ShapeInfo {
   gchar *name;
@@ -154,7 +184,12 @@
   ShapeAspectType aspect_type;
   real aspect_min, aspect_max;
 
+  real default_width;  /* default_width normalized in points */
+  real default_height; /* default_height normalized in points */
+
   GList *display_list;
+  
+  GList *subshapes;
 
   DiaObjectType *object_type; /* back link so we can find the correct type */
   
@@ -171,6 +206,9 @@
 ShapeInfo *shape_info_get(ObjectNode obj_node);
 ShapeInfo *shape_info_getbyname(const gchar *name);
 
+real shape_info_get_default_width(ShapeInfo *info);
+real shape_info_get_default_height(ShapeInfo *info);
+
 void shape_info_realise(ShapeInfo* info);
 void shape_info_print(ShapeInfo *info);
 



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