changeset 84:42698de1f653

Support translate() function for transform attribute of 'g' tag.
author Thinker K.F. Li <thinker@branda.to>
date Fri, 22 Aug 2008 12:52:48 +0800
parents ea758bb3bbe2
children 9b4a02bcaeb1
files examples/svg2code_ex/main.c examples/svg2code_ex/svg2code_ex.svg img/madbutterfly.svg src/X_supp.c tools/mb_c_header.m4 tools/mb_c_source.m4 tools/svg2code.py
diffstat 7 files changed, 364 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/examples/svg2code_ex/main.c	Fri Aug 22 00:12:04 2008 +0800
+++ b/examples/svg2code_ex/main.c	Fri Aug 22 12:52:48 2008 +0800
@@ -12,9 +12,25 @@
 static void file_button_handler(event_t *evt, void *arg) {
     ex_rt_t *ex_rt = (ex_rt_t *)arg;
 
-    coord_show(ex_rt->code->file_menu);
-    rdman_coord_changed(ex_rt->rt->rdman, ex_rt->code->file_menu);
-    rdman_redraw_changed(ex_rt->rt->rdman);
+    switch(evt->type) {
+    case EVT_MOUSE_BUT_PRESS:
+	coord_show(ex_rt->code->file_menu);
+	rdman_coord_changed(ex_rt->rt->rdman, ex_rt->code->file_menu);
+	rdman_redraw_changed(ex_rt->rt->rdman);
+	break;
+    }
+}
+
+static void file_menu_handler(event_t *evt, void *arg) {
+    ex_rt_t *ex_rt = (ex_rt_t *)arg;
+
+    switch(evt->type) {
+    case EVT_MOUSE_BUT_PRESS:
+	coord_hide(ex_rt->code->file_menu);
+	rdman_coord_changed(ex_rt->rt->rdman, ex_rt->code->file_menu);
+	rdman_redraw_changed(ex_rt->rt->rdman);
+	break;
+    }
 }
 
 int main(int argc, char * const argv[]) {
@@ -34,6 +50,8 @@
     ex_rt.rt = &rt;
     ex_rt.code = svg2code;
     subject_add_observer(factory, subject, file_button_handler, &ex_rt);
+    subject = coord_get_mouse_event(svg2code->file_menu);
+    subject_add_observer(factory, subject, file_menu_handler, &ex_rt);
 
     X_MB_handle_connection(&rt);
 
--- a/examples/svg2code_ex/svg2code_ex.svg	Fri Aug 22 00:12:04 2008 +0800
+++ b/examples/svg2code_ex/svg2code_ex.svg	Fri Aug 22 12:52:48 2008 +0800
@@ -228,40 +228,6 @@
        y="60.644024"
        rx="4.0216751"
        ry="5.0559778" />
-    <g
-       id="file_menu"
-       transform="translate(20,40)"
-       style="display:none">
-      <rect
-         y="1.9914488"
-         x="0.45847189"
-         height="237.55008"
-         width="232.80074"
-         id="rect3157"
-         style="opacity:0.5;fill:url(#radialGradient3165);fill-opacity:1;stroke:#000000;stroke-width:0.91694379;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
-      <rect
-         y="6.8649535"
-         x="6.9150982"
-         height="219.88747"
-         width="215.13812"
-         id="rect2160"
-         style="opacity:0.5;fill:url(#linearGradient3153);fill-opacity:1;stroke:#000000;stroke-width:1.16530466;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
-      <text
-         sodipodi:linespacing="125%"
-         style="font-size:16px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans"
-         id="text3134"
-         y="46.360161"
-         x="32.16227"
-         xml:space="preserve"><tspan
-           y="46.360161"
-           x="32.16227"
-           id="tspan3136"
-           sodipodi:role="line">test</tspan><tspan
-           id="tspan3138"
-           y="66.360161"
-           x="32.16227"
-           sodipodi:role="line">test</tspan></text>
-    </g>
     <rect
        style="opacity:1;fill:#f9f9f9;fill-opacity:1;stroke:#000000;stroke-width:0.93608844;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
        id="rect5130"
@@ -304,5 +270,39 @@
            id="tspan8073"
            sodipodi:role="line">檔案</tspan></text>
     </g>
+    <g
+       id="file_menu"
+       transform="translate(20,40)"
+       style="display:none">
+      <rect
+         y="1.9914488"
+         x="0.45847189"
+         height="237.55008"
+         width="232.80074"
+         id="rect3157"
+         style="opacity:0.5;fill:url(#radialGradient3165);fill-opacity:1;stroke:#000000;stroke-width:0.91694379;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <rect
+         y="6.8649535"
+         x="6.9150982"
+         height="219.88747"
+         width="215.13812"
+         id="rect2160"
+         style="opacity:0.5;fill:url(#linearGradient3153);fill-opacity:1;stroke:#000000;stroke-width:1.16530466;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <text
+         sodipodi:linespacing="125%"
+         style="font-size:16px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+         id="text3134"
+         y="46.360161"
+         x="32.16227"
+         xml:space="preserve"><tspan
+           y="46.360161"
+           x="32.16227"
+           id="tspan3136"
+           sodipodi:role="line">test</tspan><tspan
+           id="tspan3138"
+           y="66.360161"
+           x="32.16227"
+           sodipodi:role="line">test</tspan></text>
+    </g>
   </g>
 </svg>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/img/madbutterfly.svg	Fri Aug 22 12:52:48 2008 +0800
@@ -0,0 +1,241 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="200"
+   height="200"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.45.1"
+   version="1.0"
+   sodipodi:docbase="/usr/home/thinker/progm/MadButterfly/img"
+   sodipodi:docname="madbutterfly.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs4">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient8035">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop8037" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop8039" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4145">
+      <stop
+         style="stop-color:#008000;stop-opacity:1;"
+         offset="0"
+         id="stop4147" />
+      <stop
+         style="stop-color:#008000;stop-opacity:0.54639173;"
+         offset="1"
+         id="stop4149" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4134">
+      <stop
+         style="stop-color:#000080;stop-opacity:1;"
+         offset="0"
+         id="stop4136" />
+      <stop
+         style="stop-color:#000080;stop-opacity:0.65979379;"
+         offset="1"
+         id="stop4138" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3155">
+      <stop
+         style="stop-color:#808000;stop-opacity:1;"
+         offset="0"
+         id="stop3157" />
+      <stop
+         style="stop-color:#808000;stop-opacity:0;"
+         offset="1"
+         id="stop3159" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2164">
+      <stop
+         style="stop-color:#ff0000;stop-opacity:1;"
+         offset="0"
+         id="stop2166" />
+      <stop
+         style="stop-color:#ff0000;stop-opacity:0.29896906;"
+         offset="1"
+         id="stop2168" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2164"
+       id="radialGradient2170"
+       cx="243.63586"
+       cy="107.18027"
+       fx="243.63586"
+       fy="107.18027"
+       r="79.839772"
+       gradientTransform="matrix(0.7138308,0.8129738,-0.656456,0.5764012,-3.9202139,-158.52915)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4134"
+       id="linearGradient4143"
+       gradientUnits="userSpaceOnUse"
+       x1="87.598946"
+       y1="152.50659"
+       x2="84.432716"
+       y2="165.69922" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4145"
+       id="linearGradient4151"
+       x1="122.69129"
+       y1="99.208443"
+       x2="123.12633"
+       y2="84.189491"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4134"
+       id="linearGradient8031"
+       gradientUnits="userSpaceOnUse"
+       x1="87.598946"
+       y1="152.50659"
+       x2="84.432716"
+       y2="165.69922" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient8035"
+       id="radialGradient8041"
+       cx="77.427673"
+       cy="113.25273"
+       fx="77.427673"
+       fy="113.25273"
+       r="9.7625332"
+       gradientTransform="matrix(0.4496916,2.6403222,-0.8973659,6.9775647e-2,144.23825,-99.276272)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient8035"
+       id="radialGradient8045"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.4496916,2.6403222,-0.8973659,6.9775647e-2,144.23825,-99.276272)"
+       cx="77.427673"
+       cy="113.25273"
+       fx="77.427673"
+       fy="113.25273"
+       r="9.7625332" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.895"
+     inkscape:cx="100"
+     inkscape:cy="105.24277"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     width="200px"
+     height="200px"
+     inkscape:window-width="822"
+     inkscape:window-height="609"
+     inkscape:window-x="320"
+     inkscape:window-y="129" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       style="fill:url(#radialGradient2170);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 120.84433,50.131926 C 133.14255,35.928559 152.50196,23.10275 172.03167,46.437995 C 208.71237,90.266248 148.28496,117.1504 148.28496,117.1504 C 148.28496,117.1504 189.44591,111.87335 176.2533,151.45119 C 163.06069,191.02903 117.6781,108.70713 117.6781,108.70713 C 112.40106,99.736147 135.09235,187.3351 108.17942,178.36412 C 81.266491,169.39314 90.237467,141.95251 90.237467,141.95251 C 90.237467,141.95251 8.9709762,165.17151 21.635884,107.12401 C 34.300791,49.076517 76.51715,68.601583 76.51715,68.601583 C 76.51715,69.129287 86.015831,67.546174 108.17942,82.321899 L 109.23483,81.794195 C 104.48549,71.240105 120.84433,50.131926 120.84433,50.131926 z "
+       id="path2162"
+       sodipodi:nodetypes="cscscscscccc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 58.047493,51.187335 C 58.047493,50.483729 58.047493,50.483729 58.047493,51.187335 C 58.047493,57.9544 71.204408,36.903616 75.989446,41.688654 C 78.421154,44.120362 75.451956,50.708555 74.934037,53.298153 C 74.560893,55.16387 77.981581,55.613482 79.683377,56.46438 C 85.307356,59.276369 72.355982,62.269129 84.432718,62.269129 C 86.466317,62.269129 88.508148,66.322287 91.292876,67.018469 C 98.224806,68.751451 104.24543,74.501494 106.0686,81.794195 C 106.27171,82.606602 106.34046,78.560006 106.06861,78.627968"
+       id="path2176"
+       sodipodi:nodetypes="csssssssc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 88.654353,20.05277 C 89.6818,24.162555 97.209476,20.080733 101.31927,21.108179 C 106.10641,22.304966 108.32413,27.772517 107.65172,31.134564 C 107.06828,34.051779 104.54305,36.181391 103.95779,38.522427 C 102.53623,44.208644 113.44114,36.426933 105.5409,44.327176 C 101.0676,48.800477 105.5409,45.813958 105.5409,51.187335 C 105.5409,56.565846 103.95779,59.728287 103.95779,63.324538 C 103.95779,66.753036 104.82215,68.892791 105.5409,71.76781 C 105.85847,73.038092 107.20739,75.267538 107.65172,77.044855"
+       id="path2178" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:url(#linearGradient4151);fill-opacity:1;stroke:#000000;stroke-width:0.51204318;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path2182"
+       sodipodi:cx="122.69129"
+       sodipodi:cy="99.208443"
+       sodipodi:rx="6.5963058"
+       sodipodi:ry="19.525066"
+       d="M 129.2876 99.208443 A 6.5963058 19.525066 0 1 1  116.09499,99.208443 A 6.5963058 19.525066 0 1 1  129.2876 99.208443 z"
+       transform="matrix(0.6642098,-0.2778944,0.5111422,1.2217072,-16.635097,13.155406)" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.9;fill:url(#linearGradient4143);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path3163"
+       sodipodi:cx="87.598946"
+       sodipodi:cy="157.25594"
+       sodipodi:rx="8.4432716"
+       sodipodi:ry="12.137203"
+       d="M 96.042217 157.25594 A 8.4432716 12.137203 0 1 1  79.155674,157.25594 A 8.4432716 12.137203 0 1 1  96.042217 157.25594 z"
+       transform="translate(18.469657,-5.8047497)" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.9;fill:url(#linearGradient8031);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path8029"
+       sodipodi:cx="87.598946"
+       sodipodi:cy="157.25594"
+       sodipodi:rx="8.4432716"
+       sodipodi:ry="12.137203"
+       d="M 96.042217 157.25594 A 8.4432716 12.137203 0 1 1  79.155674,157.25594 A 8.4432716 12.137203 0 1 1  96.042217 157.25594 z"
+       transform="matrix(0.7243724,-0.6894089,0.6894089,0.7243724,-20.416713,78.933457)" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:url(#radialGradient8041);fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path8033"
+       sodipodi:cx="76.781006"
+       sodipodi:cy="113.45647"
+       sodipodi:rx="9.7625332"
+       sodipodi:ry="18.997362"
+       d="M 86.543539 113.45647 A 9.7625332 18.997362 0 1 1  67.018473,113.45647 A 9.7625332 18.997362 0 1 1  86.543539 113.45647 z"
+       transform="matrix(0.6298786,-0.2445212,0.3618914,0.9322203,1.607398,16.438249)" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:url(#radialGradient8045);fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path8043"
+       sodipodi:cx="76.781006"
+       sodipodi:cy="113.45647"
+       sodipodi:rx="9.7625332"
+       sodipodi:ry="18.997362"
+       d="M 86.543539 113.45647 A 9.7625332 18.997362 0 1 1  67.018473,113.45647 A 9.7625332 18.997362 0 1 1  86.543539 113.45647 z"
+       transform="matrix(0.6298786,-0.2445212,0.3618914,0.9322203,43.823751,1.4329423)" />
+  </g>
+</svg>
--- a/src/X_supp.c	Fri Aug 22 00:12:04 2008 +0800
+++ b/src/X_supp.c	Fri Aug 22 12:52:48 2008 +0800
@@ -43,14 +43,13 @@
  * for a shape is returned by sh_get_mouse_event_subject().
  */
 static void notify_shapes(redraw_man_t *rdman,
+			  shape_t *shape,
 			  co_aix x, co_aix y, int etype,
 			  unsigned int state,
 			  unsigned int button) {
     mouse_event_t mouse_event;
-    shape_t *shape;
     subject_t *subject;
     ob_factory_t *factory;
-    int in_stroke;
 
     mouse_event.event.type = etype;
     mouse_event.x = x;
@@ -58,10 +57,6 @@
     mouse_event.but_state = state;
     mouse_event.button = button;
     
-    shape = find_shape_at_pos(rdman, x, y,
-			      &in_stroke);
-    if(shape == NULL)
-	return;
     subject = sh_get_mouse_event_subject(shape);
     factory = rdman_get_ob_factory(rdman);
     
@@ -82,7 +77,10 @@
     int eflag = 0;
     int ex1=0, ey1=0, ex2=0, ey2=0;
 
+    shape_t *shape;
+
     unsigned int state, button;
+    int in_stroke;
     int r;
 
     while(XEventsQueued(display, QueuedAfterReading) > 0) {
@@ -98,8 +96,11 @@
 	    state = get_button_state(bevt->state);
 	    button = get_button(bevt->button);
 
-	    notify_shapes(rdman, x, y, EVT_MOUSE_BUT_PRESS,
-			  state, button);
+	    shape = find_shape_at_pos(rdman, x, y,
+				      &in_stroke);
+	    if(shape)
+		notify_shapes(rdman, shape, x, y, EVT_MOUSE_BUT_PRESS,
+			      state, button);
 	    break;
 
 	case ButtonRelease:
@@ -109,8 +110,11 @@
 	    state = get_button_state(bevt->state);
 	    button = get_button(bevt->button);
 
-	    notify_shapes(rdman, x, y, EVT_MOUSE_BUT_RELEASE,
-			  state, button);
+	    shape = find_shape_at_pos(rdman, x, y,
+				      &in_stroke);
+	    if(shape)
+		notify_shapes(rdman, shape, x, y, EVT_MOUSE_BUT_RELEASE,
+			      state, button);
 	    break;
 
 	case MotionNotify:
@@ -119,7 +123,26 @@
 	    y = mevt->y;
 	    state = get_button_state(mevt->state);
 
-	    notify_shapes(rdman, x, y, EVT_MOUSE_MOVE, state, 0);
+	    shape = find_shape_at_pos(rdman, x, y,
+				      &in_stroke);
+	    if(shape != NULL) {
+		if(rt->last != shape) {
+		    if(rt->last)
+			notify_shapes(rdman, rt->last, x, y,
+				      EVT_MOUSE_OUT, state, 0);
+		    notify_shapes(rdman, shape, x, y,
+				  EVT_MOUSE_OVER, state, 0);
+		    rt->last = shape;
+		} else
+		    notify_shapes(rdman, shape, x, y,
+				  EVT_MOUSE_MOVE, state, 0);
+	    } else {
+		if(rt->last) {
+		    notify_shapes(rdman, rt->last, x, y,
+				  EVT_MOUSE_OUT, state, 0);
+		    rt->last = NULL;
+		}
+	    }
 	    break;
 
 	case Expose:
@@ -249,7 +272,8 @@
 	return ERR;
     }
 
-    XSelectInput(display, win, PointerMotionMask | ExposureMask);
+    XSelectInput(display, win, PointerMotionMask | ExposureMask |
+		 ButtonPressMask | ButtonReleaseMask);
     XFlush(display);
 
     *displayp = display;
--- a/tools/mb_c_header.m4	Fri Aug 22 00:12:04 2008 +0800
+++ b/tools/mb_c_header.m4	Fri Aug 22 12:52:48 2008 +0800
@@ -36,6 +36,7 @@
 define([GROUP_HIDE],)
 define([PATH_HIDE],)
 define([RECT_HIDE],)
+define([COORD_TRANSLATE],)
 
 define([MADBUTTERFLY],[dnl
 [#ifndef __$1_H_
--- a/tools/mb_c_source.m4	Fri Aug 22 00:12:04 2008 +0800
+++ b/tools/mb_c_source.m4	Fri Aug 22 12:52:48 2008 +0800
@@ -46,6 +46,7 @@
 define([GROUP_HIDE],)
 define([RECT_HIDE],)
 define([PATH_HIDE],)
+define([COORD_TRANSLATE],)
 divert[]])
 
 define([S_ADD_LINEAR_PAINT],[
@@ -133,6 +134,15 @@
 [    sh_hide(obj->$1);
 ]])
 
+define([S_COORD_TRANSLATE],[dnl
+[    memset(obj->$1->matrix, 0, sizeof(obj->$1->matrix));
+    obj->$1->matrix[0] = 1;
+    obj->$1->matrix[2] = $2;
+    obj->$1->matrix[4] = 1;
+    obj->$1->matrix[5] = $3;
+    rdman_coord_changed(rdman, obj->$1);
+]])
+
 define([SETUP_VARS],[divert([-1])
 define([SIMPORT],[IMPORT(]QUOTE($[]1)[,[S_])])
 SIMPORT([ADD_LINEAR_PAINT])
@@ -152,6 +162,7 @@
 SIMPORT([GROUP_HIDE])
 SIMPORT([RECT_HIDE])
 SIMPORT([PATH_HIDE])
+SIMPORT([COORD_TRANSLATE])
 divert[]])
 
 define([F_ADD_LINEAR_PAINT],[[
@@ -205,6 +216,7 @@
 define([GROUP_HIDE],)
 define([RECT_HIDE],)
 define([PATH_HIDE],)
+define([COORD_TRANSLATE],)
 divert[]])
 
 define([MADBUTTERFLY],[dnl
--- a/tools/svg2code.py	Fri Aug 22 00:12:04 2008 +0800
+++ b/tools/svg2code.py	Fri Aug 22 12:52:48 2008 +0800
@@ -1,6 +1,7 @@
 #! /usr/bin/env python
 from xml.dom.minidom import parse
 import sys
+import re
 
 svgns='http://www.w3.org/2000/svg'
 xlinkns='http://www.w3.org/1999/xlink'
@@ -249,10 +250,28 @@
         pass
     pass
 
+reo_translate = re.compile('translate\\(([0-9]+),([0-9]+)\\)')
+def translate_transform(coord_id, transform, codefo):
+    transform = transform.strip()
+    mo = reo_translate.match(transform)
+    if mo:
+        x = float(mo.group(1))
+        y = float(mo.group(2))
+        print >> codefo, 'COORD_TRANSLATE([%s], %f, %f)dnl' % (
+            coord_id, x, y)
+        pass
+    pass
+
 def translate_group(group, parent_id, codefo, doc):
     group_id = group.getAttribute('id')
     print >> codefo, 'dnl'
     print >> codefo, 'ADD_COORD([%s], [%s])dnl' % (group_id, parent_id)
+
+    if group.hasAttribute('transform'):
+        transform = group.getAttribute('transform')
+        translate_transform(group_id, transform, codefo)
+        pass
+
     translate_style(group, group_id, codefo, doc, 'GROUP_')
     for node in group.childNodes:
         if node.namespaceURI != svgns: