1 /*
2 * Copyright (C) 2009 - 2011 Vivien Malerba <malerba@gnome-db.org>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "browser-canvas-utility.h"
20 #include <math.h>
21 #include <string.h>
22
23 static gboolean compute_intersect_rect_line (gdouble rectx1, gdouble recty1, gdouble rectx2, gdouble recty2,
24 gdouble P1x, gdouble P1y, gdouble P2x, gdouble P2y,
25 gdouble *R1x, gdouble *R1y, gdouble *R2x, gdouble *R2y);
26
27 static void compute_text_marks_offsets (gdouble x1, gdouble y1, gdouble x2, gdouble y2,
28 gdouble *xoff, gdouble *yoff, GooCanvasAnchorType *anchor_type);
29
30 static GSList *browser_canvas_canvas_shape_add_to_list (GSList *list, gchar *swallow_id, GooCanvasItem *item);
31 static BrowserCanvasCanvasShape *browser_canvas_canvas_shape_find (GSList *list, const gchar *id);
32
33
34 /*
35 * Computes the points' coordinates of the line going from
36 * @ref_pk_ent to @fk_ent (which are themselves rectangles)
37 *
38 * if @shapes is not NULL, then the shapes in the list are reused, and the ones which don't need
39 * to exist anymore are removed
40 *
41 * Returns a list of BrowserCanvasCanvasShapes structures
42 */
43 GSList *
browser_canvas_util_compute_anchor_shapes(GooCanvasItem * parent,GSList * shapes,BrowserCanvasTable * fk_ent,BrowserCanvasTable * ref_pk_ent,guint nb_anchors,guint ext,gboolean with_handle)44 browser_canvas_util_compute_anchor_shapes (GooCanvasItem *parent, GSList *shapes,
45 BrowserCanvasTable *fk_ent, BrowserCanvasTable *ref_pk_ent,
46 guint nb_anchors, guint ext, gboolean with_handle)
47 {
48 GSList *retval = shapes;
49 guint i;
50 gdouble fx1, fy1, fx2, fy2; /* FK entity item (bounds) */
51 gdouble rx1, ry1, rx2, ry2; /* REF PK entity item (bounds) */
52
53 BrowserCanvasCanvasShape *shape;
54 gchar *id;
55
56 gdouble rcx, rcy; /* center of ref_pk entity item */
57 gdouble cx, cy;
58
59 gdouble rux, ruy; /* current ref_pk point for the arrow line */
60 gdouble dx, dy; /* increments to compute the new ref_pk point for the arrow line */
61 GooCanvasBounds bounds;
62
63 g_return_val_if_fail (nb_anchors > 0, NULL);
64
65 browser_canvas_table_get_anchor_bounds (fk_ent, &bounds);
66 fx1 = bounds.x1;
67 fy1 = bounds.y1;
68 fx2 = bounds.x2;
69 fy2 = bounds.y2;
70 browser_canvas_table_get_anchor_bounds (ref_pk_ent, &bounds);
71 rx1 = bounds.x1;
72 ry1 = bounds.y1;
73 rx2 = bounds.x2;
74 ry2 = bounds.y2;
75
76 /* compute the cx, cy, dx and dy values */
77 rcx = (rx1 + rx2) / 2.;
78 rcy = (ry1 + ry2) / 2.;
79 cx = (fx1 + fx2) / 2.;
80 cy = (fy1 + fy2) / 2.;
81 rux = rcx;
82 ruy = rcy;
83 dx = 0;
84 dy = 0;
85
86 for (i = 0; i < nb_anchors; i++) {
87 /* TODO:
88 - detect tables overlapping
89 */
90 if ((rcx == cx) && (rcy == cy)) {
91 /* tables have the same center (includes case when they are equal) */
92 gdouble Dy, Dx;
93 GooCanvasPoints *ap, *points;
94 GooCanvasItem *item;
95
96 points = goo_canvas_points_new (4);
97 ap = goo_canvas_points_new (4);
98
99 Dy = (ry2 - ry1) / 2. / (gdouble ) (nb_anchors + 1) * (gdouble) (i + 1);
100 Dx = (rx2 - rx1) * (0.8 + 0.1 * i);
101 if (! compute_intersect_rect_line (rx1, ry1, rx2, ry2,
102 cx, cy, cx + Dx, cy - Dy,
103 &(ap->coords[0]), &(ap->coords[1]),
104 &(ap->coords[2]), &(ap->coords[3])))
105 return retval;
106
107 if (ap->coords[0] > ap->coords[2]) {
108 points->coords[0] = ap->coords[0];
109 points->coords[1] = ap->coords[1];
110 }
111 else {
112 points->coords[0] = ap->coords[2];
113 points->coords[1] = ap->coords[3];
114 }
115
116 points->coords[2] = cx + Dx;
117 points->coords[3] = cy - Dy;
118
119 Dy = (fy2 - fy1) / 2. / (gdouble ) (nb_anchors + 1) * (gdouble) (i + 1);
120 Dx = (fx2 - fx1) * (0.8 + 0.1 * i);
121 points->coords[4] = cx + Dx;
122 points->coords[5] = cy + Dy;
123
124 if (! compute_intersect_rect_line (fx1, fy1, fx2, fy2,
125 cx, cy, cx + Dx, cy + Dy,
126 &(ap->coords[0]), &(ap->coords[1]),
127 &(ap->coords[2]), &(ap->coords[3])))
128 return retval;
129
130 if (ap->coords[0] > ap->coords[2]) {
131 points->coords[6] = ap->coords[0];
132 points->coords[7] = ap->coords[1];
133 }
134 else {
135 points->coords[6] = ap->coords[2];
136 points->coords[7] = ap->coords[3];
137 }
138
139 id = g_strdup_printf ("a%d", i);
140 shape = browser_canvas_canvas_shape_find (retval, id);
141 if (shape) {
142 g_object_set (shape->item, "points", points, NULL);
143 shape->_used = TRUE;
144 g_free (id);
145 }
146 else {
147 item = goo_canvas_polyline_new_line (parent,
148 points->coords[0], points->coords [1],
149 points->coords[2], points->coords [3],
150 "close-path", FALSE,
151 "points", points, NULL);
152 retval = browser_canvas_canvas_shape_add_to_list (retval, id, item);
153 }
154 goo_canvas_points_unref (ap);
155
156 /* extension marks as text */
157 if (ext & CANVAS_SHAPE_EXT_JOIN_OUTER_1) {
158 id = g_strdup_printf ("a%de1", i);
159 shape = browser_canvas_canvas_shape_find (retval, id);
160 if (shape) {
161 g_object_set (shape->item,
162 "x", points->coords[2] + 5.,
163 "y", points->coords[3] - 5., NULL);
164 shape->_used = TRUE;
165 g_free (id);
166 }
167 else {
168 item = goo_canvas_text_new (parent, "*",
169 points->coords[2] + 5.,
170 points->coords[3] - 5., -1,
171 GOO_CANVAS_ANCHOR_SOUTH, NULL);
172 retval = browser_canvas_canvas_shape_add_to_list (retval, id, item);
173 }
174 }
175
176 if (ext & CANVAS_SHAPE_EXT_JOIN_OUTER_2) {
177 id = g_strdup_printf ("a%de2", i);
178 if (shape) {
179 g_object_set (shape->item,
180 "x", points->coords[4] + 5.,
181 "y", points->coords[5] + 5., NULL);
182 shape->_used = TRUE;
183 g_free (id);
184 }
185 else {
186 item = goo_canvas_text_new (parent, "*",
187 points->coords[4] + 5.,
188 points->coords[5] + 5., -1,
189 GOO_CANVAS_ANCHOR_NORTH, NULL);
190 retval = browser_canvas_canvas_shape_add_to_list (retval, id, item);
191 }
192 }
193
194 goo_canvas_points_unref (points);
195 }
196 else {
197 GooCanvasPoints *ap, *points;
198 GooCanvasItem *item;
199
200 points = goo_canvas_points_new (2);
201 ap = goo_canvas_points_new (4);
202
203 if (nb_anchors > 1) {
204 if ((dx == 0) && (dy == 0)) {
205 /* compute perpendicular to D={(rcx, rcy), (cx, cy)} */
206 gdouble vx = (rcx - cx), vy = (rcy - cy);
207 gdouble tmp;
208
209 tmp = vx;
210 vx = vy;
211 vy = - tmp;
212
213 /* compute intersect of ref_pkey rectangle and D=[vx, vy] passing at (rcx, rcy) */
214 if (! compute_intersect_rect_line (rx1, ry1, rx2, ry2,
215 rcx, rcy, rcx + vx, rcy + vy,
216 &(ap->coords[0]), &(ap->coords[1]),
217 &(ap->coords[2]), &(ap->coords[3])))
218 return retval;
219 dx = (ap->coords[2] - ap->coords[0]) / (gdouble) (nb_anchors + 1);
220 dy = (ap->coords[3] - ap->coords[1]) / (gdouble) (nb_anchors + 1);
221 rux = ap->coords[0];
222 ruy = ap->coords[1];
223 }
224
225 rux += dx;
226 ruy += dy;
227 }
228
229 /* compute the 4 intersection points */
230 if (! compute_intersect_rect_line (rx1, ry1, rx2, ry2,
231 rux, ruy, cx, cy,
232 &(ap->coords[0]), &(ap->coords[1]),
233 &(ap->coords[2]), &(ap->coords[3])))
234 return retval;
235 if (! compute_intersect_rect_line (fx1, fy1, fx2, fy2,
236 rux, ruy, cx, cy,
237 &(ap->coords[4]), &(ap->coords[5]),
238 &(ap->coords[6]), &(ap->coords[7])))
239 return retval;
240
241 /* choosing between point coords(0,1) and coords(2,3) */
242 if (((ap->coords[0] - ap->coords[4]) * (ap->coords[0] - ap->coords[4]) +
243 (ap->coords[1] - ap->coords[5]) * (ap->coords[1] - ap->coords[5])) <
244 ((ap->coords[2] - ap->coords[4]) * (ap->coords[2] - ap->coords[4]) +
245 (ap->coords[3] - ap->coords[5]) * (ap->coords[3] - ap->coords[5]))) {
246 points->coords[0] = ap->coords[0];
247 points->coords[1] = ap->coords[1];
248 }
249 else {
250 points->coords[0] = ap->coords[2];
251 points->coords[1] = ap->coords[3];
252 }
253
254 /* choosing between point coords(4,5) and coords(6,7) */
255 if (((points->coords[0] - ap->coords[4]) * (points->coords[0] - ap->coords[4]) +
256 (points->coords[1] - ap->coords[5]) * (points->coords[1] - ap->coords[5])) <
257 ((points->coords[0] - ap->coords[6]) * (points->coords[0] - ap->coords[6]) +
258 (points->coords[1] - ap->coords[7]) * (points->coords[1] - ap->coords[7]))) {
259 points->coords[2] = ap->coords[4];
260 points->coords[3] = ap->coords[5];
261 }
262 else {
263 points->coords[2] = ap->coords[6];
264 points->coords[3] = ap->coords[7];
265 }
266
267 id = g_strdup_printf ("a%d", i);
268 shape = browser_canvas_canvas_shape_find (retval, id);
269 if (shape) {
270 g_object_set (shape->item, "points", points, NULL);
271 shape->_used = TRUE;
272 g_free (id);
273 }
274 else {
275 item = goo_canvas_polyline_new_line (parent,
276 points->coords[0], points->coords [1],
277 points->coords[2], points->coords [3],
278 "close-path", FALSE,
279 "points", points, NULL);
280 retval = browser_canvas_canvas_shape_add_to_list (retval, id, item);
281 }
282 goo_canvas_points_unref (ap);
283
284 /* extension marks as text */
285 if (ext & CANVAS_SHAPE_EXT_JOIN_OUTER_1) {
286 gdouble mxoff = 0., myoff = 0.;
287 GooCanvasAnchorType atype;
288
289 compute_text_marks_offsets (points->coords[0], points->coords[1],
290 points->coords[2], points->coords[3],
291 &mxoff, &myoff, &atype);
292 id = g_strdup_printf ("a%de1", i);
293 shape = browser_canvas_canvas_shape_find (retval, id);
294 if (shape) {
295 g_object_set (shape->item,
296 "x", points->coords[2] + mxoff,
297 "y", points->coords[3] + myoff,
298 "anchor", atype, NULL);
299 shape->_used = TRUE;
300 g_free (id);
301 }
302 else {
303 item = goo_canvas_text_new (parent, "*",
304 points->coords[2] + mxoff,
305 points->coords[3] + myoff, -1,
306 atype, NULL);
307 retval = browser_canvas_canvas_shape_add_to_list (retval, id, item);
308 }
309 }
310
311 if (ext & CANVAS_SHAPE_EXT_JOIN_OUTER_2) {
312 gdouble mxoff, myoff;
313 GooCanvasAnchorType atype;
314
315 compute_text_marks_offsets (points->coords[2], points->coords[3],
316 points->coords[0], points->coords[1],
317 &mxoff, &myoff, &atype);
318
319 id = g_strdup_printf ("a%de2", i);
320 if (shape) {
321 g_object_set (shape->item,
322 "x", points->coords[0] + mxoff,
323 "y", points->coords[1] + myoff,
324 "anchor", atype, NULL);
325 shape->_used = TRUE;
326 g_free (id);
327 }
328 else {
329 item = goo_canvas_text_new (parent, "*",
330 points->coords[0] + mxoff,
331 points->coords[1] + myoff, -1,
332 atype, NULL);
333 retval = browser_canvas_canvas_shape_add_to_list (retval, id, item);
334 }
335 }
336
337 goo_canvas_points_unref (points);
338 }
339 }
340
341 return retval;
342 }
343
344 /*
345 * Computes the position offsets, relative to X2=(x2, y2) of a text to be written
346 * close to the X2 point, also computes the anchor type
347 */
348 static void
compute_text_marks_offsets(gdouble x1,gdouble y1,gdouble x2,gdouble y2,gdouble * xoff,gdouble * yoff,GooCanvasAnchorType * anchor_type)349 compute_text_marks_offsets (gdouble x1, gdouble y1, gdouble x2, gdouble y2,
350 gdouble *xoff, gdouble *yoff, GooCanvasAnchorType *anchor_type)
351 {
352 gdouble mxoff, myoff;
353 GooCanvasAnchorType atype = GOO_CANVAS_ANCHOR_CENTER; /* FIXME */
354 gdouble sint, cost;
355 gdouble sina = 0.5;
356 gdouble cosa = 0.866025; /* sqrt(3)/2 */
357 gdouble hyp;
358 gdouble d = 15.;
359
360 hyp = sqrt ((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1));
361 sint = - (y2 - y1) / hyp;
362 cost = (x2 - x1) / hyp;
363
364 mxoff = -d * (sina * sint + cosa * cost);
365 myoff = -d * (sina * cost - cosa * sint);
366
367 if (xoff)
368 *xoff = mxoff;
369 if (yoff)
370 *yoff = myoff;
371 if (anchor_type)
372 *anchor_type = atype;
373 }
374
375 /*
376 * Computes the points of intersection between a rectangle (defined by the first 2 points)
377 * and a line (defined by the next 2 points).
378 *
379 * The result is returned in place of the line's point definition
380 *
381 * --------- ----- D1
382 * | |
383 * | |
384 * | |
385 * | |
386 * | |
387 * | |
388 * | |
389 * --------- ---- D2
390 *
391 * | |
392 * | |
393 * D3 D4
394 *
395 * Returns: TRUE if the line crosses the rectangle, and FALSE if it misses it.
396 */
397 static gboolean
compute_intersect_rect_line(gdouble rectx1,gdouble recty1,gdouble rectx2,gdouble recty2,gdouble P1x,gdouble P1y,gdouble P2x,gdouble P2y,gdouble * R1x,gdouble * R1y,gdouble * R2x,gdouble * R2y)398 compute_intersect_rect_line (gdouble rectx1, gdouble recty1, gdouble rectx2, gdouble recty2,
399 gdouble P1x, gdouble P1y, gdouble P2x, gdouble P2y,
400 gdouble *R1x, gdouble *R1y, gdouble *R2x, gdouble *R2y)
401 {
402 gboolean retval = FALSE;
403 gboolean rotated = FALSE;
404 gdouble a=0.; /* line slope y = a x + b */
405 gdouble b; /* line offset y = a x + b */
406 gdouble offset = 2.;
407
408 gdouble ptsx[4]; /* points' X coordinate: 0 for intersect with D1, 1 for D2,... */
409 gdouble ptsy[4]; /* points' Y coordinate */
410
411 if ((rectx1 == rectx2) && (recty1 == recty2))
412 return FALSE;
413 if ((rectx1 >= rectx2) || (recty1 >= recty2))
414 return FALSE;
415 if ((P1x == P2x) && (P1y == P2y))
416 return FALSE;
417
418 /* rotate the coordinates to invert X and Y to avoid rounding problems ? */
419 if (P1x != P2x)
420 a = (P1y - P2y) / (P1x - P2x);
421 if ((P1x == P2x) || (fabs (a) > 1)) {
422 gdouble tmp;
423 rotated = TRUE;
424 tmp = rectx1; rectx1 = recty1; recty1 = tmp;
425 tmp = rectx2; rectx2 = recty2; recty2 = tmp;
426 tmp = P1x; P1x = P1y; P1y = tmp;
427 tmp = P2x; P2x = P2y; P2y = tmp;
428 a = (P1y - P2y) / (P1x - P2x);
429 }
430
431 /* here we have (P1x != P2x), non vertical line */
432 b = P1y - a * P1x;
433
434 if (a == 0) {
435 /* horizontal line */
436
437 if ((b <= recty2) && (b >= recty1)) {
438 retval = TRUE;
439 *R1x = rectx1 - offset; *R1y = b;
440 *R2x = rectx2 + offset; *R2y = b;
441 }
442 }
443 else {
444 gdouble retx[2] = {0., 0.};
445 gdouble rety[2] = {0., 0.};
446 gint i = 0;
447
448 /* non horizontal and non vertical line */
449 /* D1 */
450 ptsy[0] = recty1 - offset;
451 ptsx[0] = (recty1 - b) / a;
452
453 /* D2 */
454 ptsy[1] = recty2 + offset;
455 ptsx[1] = (recty2 - b) / a;
456
457 /* D3 */
458 ptsx[2] = rectx1 - offset;
459 ptsy[2] = a * rectx1 + b;
460
461 /* D4 */
462 ptsx[3] = rectx2 + offset;
463 ptsy[3] = a * rectx2 + b;
464
465 if ((ptsx[0] >= rectx1) && (ptsx[0] <= rectx2)) {
466 retval = TRUE;
467 retx[i] = ptsx[0]; rety[i] = ptsy[0];
468 i ++;
469 }
470 if ((ptsx[1] >= rectx1) && (ptsx[1] <= rectx2)) {
471 retval = TRUE;
472 retx[i] = ptsx[1]; rety[i] = ptsy[1];
473 i ++;
474 }
475 if ((i<2) && (ptsy[2] >= recty1) && (ptsy[2] <= recty2)) {
476 retval = TRUE;
477 retx[i] = ptsx[2]; rety[i] = ptsy[2];
478 i ++;
479 }
480 if ((i<2) && (ptsy[3] >= recty1) && (ptsy[3] <= recty2)) {
481 retval = TRUE;
482 retx[i] = ptsx[3]; rety[i] = ptsy[3];
483 i++;
484 }
485
486 if (retval) {
487 g_assert (i == 2); /* wee need 2 points! */
488 *R1x = retx[0]; *R1y = rety[0];
489 *R2x = retx[1]; *R2y = rety[1];
490 }
491 }
492
493 if (retval && rotated) {
494 /* rotate it back */
495 gdouble tmp;
496
497 tmp = *R1x; *R1x = *R1y; *R1y = tmp;
498 tmp = *R2x; *R2x = *R2y; *R2y = tmp;
499 }
500
501 return retval;
502 }
503
504 /*
505 * Compute the anchor shapes to link field1 to field2 from ent1 to ent2
506 *
507 * if @shapes is not NULL, then the shapes in the list are reused, and the ones which don't need
508 * to exist anymore are removed
509 *
510 * Returns a list of BrowserCanvasCanvasShapes structures
511 */
512 GSList *
browser_canvas_util_compute_connect_shapes(GooCanvasItem * parent,GSList * shapes,BrowserCanvasTable * ent1,GdaMetaTableColumn * field1,BrowserCanvasTable * ent2,GdaMetaTableColumn * field2,guint nb_connect,guint ext)513 browser_canvas_util_compute_connect_shapes (GooCanvasItem *parent, GSList *shapes,
514 BrowserCanvasTable *ent1, GdaMetaTableColumn *field1,
515 BrowserCanvasTable *ent2, GdaMetaTableColumn *field2,
516 guint nb_connect, guint ext)
517 {
518 GSList *retval = shapes;
519 GooCanvasItem *item;
520 GooCanvasPoints *points;
521 gdouble xl1, xr1, xl2, xr2, yt1, yt2; /* X boundings and Y top of ent1 and ent2 */
522 gdouble x1, x2; /* X positions of the lines extremities close to ent1 and ent2 */
523 gdouble x1offset, x2offset; /* offsets for the horizontal part of the lines */
524 double sq = 5.;
525 double eps = 0.5;
526 GooCanvasBounds bounds;
527
528 BrowserCanvasCanvasShape *shape;
529 gchar *id;
530
531 if (!field1 || !field2)
532 return browser_canvas_util_compute_anchor_shapes (parent, shapes, ent1, ent2, 1, ext, FALSE);
533
534 /* line made of 4 points */
535 points = goo_canvas_points_new (4);
536 browser_canvas_table_get_anchor_bounds (ent1, &bounds);
537 xl1 = bounds.x1;
538 yt1 = bounds.y1;
539 xr1 = bounds.x2;
540 browser_canvas_table_get_anchor_bounds (ent2, &bounds);
541 xl2 = bounds.x1;
542 yt2 = bounds.y1;
543 xr2 = bounds.x2;
544
545 if (xl2 > xr1) {
546 x1 = xr1 + eps;
547 x2 = xl2 - eps;
548 x1offset = 2 * sq;
549 x2offset = -2 * sq;
550 }
551 else {
552 if (xl1 >= xr2) {
553 x1 = xl1 - eps;
554 x2 = xr2 + eps;
555 x1offset = - 2 * sq;
556 x2offset = 2 * sq;
557 }
558 else {
559 if ((xl1 + xr1) < (xl2 + xr2)) {
560 x1 = xl1 - eps;
561 x2 = xl2 - eps;
562 x1offset = -2 * sq;
563 x2offset = -2 * sq;
564 }
565 else {
566 x1 = xr1 + eps;
567 x2 = xr2 + eps;
568 x1offset = 2 * sq;
569 x2offset = 2 * sq;
570 }
571 }
572 }
573
574 points->coords[0] = x1;
575 points->coords[1] = browser_canvas_table_get_column_ypos (ent1, field1) + yt1;
576
577 points->coords[2] = x1 + x1offset;
578 points->coords[3] = points->coords[1];
579
580 points->coords[4] = x2 + x2offset;
581 points->coords[5] = browser_canvas_table_get_column_ypos (ent2, field2) + yt2;
582
583 points->coords[6] = x2;
584 points->coords[7] = points->coords[5];
585
586 id = g_strdup_printf ("c%d", nb_connect);
587 shape = browser_canvas_canvas_shape_find (retval, id);
588 if (shape) {
589 g_object_set (shape->item, "points", points, NULL);
590 shape->_used = TRUE;
591 g_free (id);
592 }
593 else {
594 item = goo_canvas_polyline_new_line (parent,
595 points->coords[0], points->coords [1],
596 points->coords[2], points->coords [3],
597 "close-path", FALSE,
598 "points", points, NULL);
599 retval = browser_canvas_canvas_shape_add_to_list (retval, id, item);
600 }
601
602 /* extension marks as text */
603 if (ext & CANVAS_SHAPE_EXT_JOIN_OUTER_1) {
604 gdouble mxoff = 0., myoff = 0.;
605 GooCanvasAnchorType atype;
606
607 compute_text_marks_offsets (points->coords[4], points->coords[5],
608 points->coords[2], points->coords[3],
609 &mxoff, &myoff, &atype);
610
611 id = g_strdup_printf ("ce%d1", nb_connect);
612 shape = browser_canvas_canvas_shape_find (retval, id);
613 if (shape) {
614 g_object_set (shape->item,
615 "x", points->coords[2] + mxoff,
616 "y", points->coords[3] + myoff,
617 "anchor", atype, NULL);
618 shape->_used = TRUE;
619 g_free (id);
620 }
621 else {
622 item = goo_canvas_text_new (parent, "*",
623 points->coords[2] + mxoff,
624 points->coords[3] + myoff, -1,
625 atype, NULL);
626 retval = browser_canvas_canvas_shape_add_to_list (retval, id, item);
627 }
628 }
629
630 if (ext & CANVAS_SHAPE_EXT_JOIN_OUTER_2) {
631 gdouble mxoff, myoff;
632 GooCanvasAnchorType atype;
633
634 compute_text_marks_offsets (points->coords[2], points->coords[3],
635 points->coords[4], points->coords[5],
636 &mxoff, &myoff, &atype);
637
638 id = g_strdup_printf ("ce%d2", nb_connect);
639 shape = browser_canvas_canvas_shape_find (retval, id);
640 if (shape) {
641 g_object_set (shape->item,
642 "x", points->coords[2] + mxoff,
643 "y", points->coords[3] + myoff,
644 "anchor", atype, NULL);
645 shape->_used = TRUE;
646 g_free (id);
647 }
648 else {
649 item = goo_canvas_text_new (parent, "*",
650 points->coords[2] + mxoff,
651 points->coords[3] + myoff, -1,
652 atype, NULL);
653 retval = browser_canvas_canvas_shape_add_to_list (retval, id, item);
654 }
655 }
656
657 goo_canvas_points_unref (points);
658
659 return retval;
660 }
661
662 static GSList *
browser_canvas_canvas_shape_add_to_list(GSList * list,gchar * swallow_id,GooCanvasItem * item)663 browser_canvas_canvas_shape_add_to_list (GSList *list, gchar *swallow_id, GooCanvasItem *item)
664 {
665 BrowserCanvasCanvasShape *shape = g_new (BrowserCanvasCanvasShape, 1);
666
667 g_assert (swallow_id);
668 g_assert (item);
669 shape->id = swallow_id;
670 shape->item = item;
671 shape->_used = TRUE;
672 shape->is_new = TRUE;
673
674 /*g_print ("Shape %p (%s: %s) added\n", item, swallow_id, G_OBJECT_TYPE_NAME (item));*/
675
676 return g_slist_append (list, shape);
677 }
678
679 static BrowserCanvasCanvasShape *
browser_canvas_canvas_shape_find(GSList * list,const gchar * id)680 browser_canvas_canvas_shape_find (GSList *list, const gchar *id)
681 {
682 BrowserCanvasCanvasShape *shape = NULL;
683 GSList *l;
684
685 for (l = list; l && !shape; l = l->next)
686 if (!strcmp (((BrowserCanvasCanvasShape*) l->data)->id, id))
687 shape = (BrowserCanvasCanvasShape*) l->data;
688
689 /*g_print ("Looking for shape %s: %s\n", id, shape ? "Found" : "Not found");*/
690 return shape;
691 }
692
693 GSList *
browser_canvas_canvas_shapes_remove_obsolete_shapes(GSList * list)694 browser_canvas_canvas_shapes_remove_obsolete_shapes (GSList *list)
695 {
696 GSList *l, *ret = list;
697
698 for (l = list; l; ) {
699 if (((BrowserCanvasCanvasShape*)(l->data))->_used) {
700 ((BrowserCanvasCanvasShape*)(l->data))->_used = FALSE;
701 l=l->next;
702 }
703 else {
704 GSList *tmp;
705 BrowserCanvasCanvasShape *shape = (BrowserCanvasCanvasShape*) l->data;
706
707 g_free (shape->id);
708 goo_canvas_item_remove (shape->item);
709 g_free (shape);
710
711 tmp = l->next;
712 ret = g_slist_delete_link (ret, l);
713 l = tmp;
714 }
715 }
716
717 return ret;
718 }
719
720 void
browser_canvas_canvas_shapes_remove_all(GSList * list)721 browser_canvas_canvas_shapes_remove_all (GSList *list)
722 {
723 GSList *l;
724
725 for (l = list; l; l = l->next) {
726 BrowserCanvasCanvasShape *shape = (BrowserCanvasCanvasShape*) l->data;
727
728 g_free (shape->id);
729 goo_canvas_item_remove (shape->item);
730 g_free (shape);
731 }
732
733 g_slist_free (list);
734 }
735
736 void
browser_canvas_canvas_shapes_dump(GSList * list)737 browser_canvas_canvas_shapes_dump (GSList *list)
738 {
739 GSList *l;
740 g_print ("Canvas shapes...\n");
741 for (l = list; l; l = l->next)
742 g_print ("\tShape %s @%p (%s: %p) %s\n", BROWSER_CANVAS_CANVAS_SHAPE (l->data)->id,
743 BROWSER_CANVAS_CANVAS_SHAPE (l->data),
744 G_OBJECT_TYPE_NAME (BROWSER_CANVAS_CANVAS_SHAPE (l->data)->item),
745 BROWSER_CANVAS_CANVAS_SHAPE (l->data)->item,
746 BROWSER_CANVAS_CANVAS_SHAPE (l->data)->_used ? "Used": "Not used");
747 }
748