1
/* mg-canvas-fkconstraint.c
3
* Copyright (C) 2004 Vivien Malerba
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License as
7
* published by the Free Software Foundation; either version 2 of the
8
* License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22
#include "mg-canvas.h"
23
#include "mg-canvas-fkconstraint.h"
24
#include "mg-canvas-entity.h"
25
#include "mg-canvas-text.h"
26
#include <libmergeant/mg-field.h>
27
#include <libmergeant/mg-db-constraint.h>
29
static void mg_canvas_fkconstraint_class_init (MgCanvasFkconstraintClass * class);
30
static void mg_canvas_fkconstraint_init (MgCanvasFkconstraint * cc);
31
static void mg_canvas_fkconstraint_dispose (GObject * object);
32
static void mg_canvas_fkconstraint_finalize (GObject * object);
34
static void mg_canvas_fkconstraint_set_property (GObject *object,
38
static void mg_canvas_fkconstraint_get_property (GObject *object,
43
static void clean_items (MgCanvasFkconstraint *cc);
44
static void create_items (MgCanvasFkconstraint *cc);
52
struct _MgCanvasFkconstraintPrivate
55
MgCanvasEntity *fk_entity_item;
56
MgCanvasEntity *ref_pk_entity_item;
59
/* get a pointer to the parents to be able to call their destructor */
60
static GObjectClass *parent_class = NULL;
63
mg_canvas_fkconstraint_get_type (void)
65
static GType type = 0;
68
static const GTypeInfo info = {
69
sizeof (MgCanvasFkconstraintClass),
71
(GBaseFinalizeFunc) NULL,
72
(GClassInitFunc) mg_canvas_fkconstraint_class_init,
75
sizeof (MgCanvasFkconstraint),
77
(GInstanceInitFunc) mg_canvas_fkconstraint_init
80
type = g_type_register_static (MG_CANVAS_ITEM_TYPE, "MgCanvasFkconstraint", &info, 0);
87
mg_canvas_fkconstraint_class_init (MgCanvasFkconstraintClass * class)
89
GObjectClass *object_class = G_OBJECT_CLASS (class);
91
parent_class = g_type_class_peek_parent (class);
93
object_class->dispose = mg_canvas_fkconstraint_dispose;
94
object_class->finalize = mg_canvas_fkconstraint_finalize;
97
object_class->set_property = mg_canvas_fkconstraint_set_property;
98
object_class->get_property = mg_canvas_fkconstraint_get_property;
99
g_object_class_install_property (object_class, PROP_FK_CONSTRAINT,
100
g_param_spec_pointer ("fk_constraint", "Latest FK constraint to add",
101
NULL, G_PARAM_WRITABLE));
106
mg_canvas_fkconstraint_init (MgCanvasFkconstraint *cc)
108
cc->priv = g_new0 (MgCanvasFkconstraintPrivate, 1);
109
cc->priv->constraints = NULL;
110
cc->priv->fk_entity_item = NULL;
111
cc->priv->ref_pk_entity_item = NULL;
115
static void entity_destroy_cb (MgCanvasEntity *entity, MgCanvasFkconstraint *cc);
116
static void constraint_nullified_cb (MgDbConstraint *fkcons, MgCanvasFkconstraint *cc);
119
mg_canvas_fkconstraint_dispose (GObject *object)
121
MgCanvasFkconstraint *cc;
122
g_return_if_fail (object != NULL);
123
g_return_if_fail (IS_MG_CANVAS_FKCONSTRAINT (object));
125
cc = MG_CANVAS_FKCONSTRAINT (object);
128
if (cc->priv->constraints) {
129
GSList *list = cc->priv->constraints;
131
g_signal_handlers_disconnect_by_func (G_OBJECT (list->data),
132
G_CALLBACK (constraint_nullified_cb), cc);
133
list = g_slist_next (list);
135
g_slist_free (cc->priv->constraints);
136
cc->priv->constraints = NULL;
139
/* for the parent class */
140
parent_class->dispose (object);
145
mg_canvas_fkconstraint_finalize (GObject *object)
147
MgCanvasFkconstraint *cc;
148
g_return_if_fail (object != NULL);
149
g_return_if_fail (IS_MG_CANVAS_FKCONSTRAINT (object));
151
cc = MG_CANVAS_FKCONSTRAINT (object);
157
/* for the parent class */
158
parent_class->finalize (object);
162
mg_canvas_fkconstraint_set_property (GObject *object,
167
MgCanvasFkconstraint *cc;
169
cc = MG_CANVAS_FKCONSTRAINT (object);
172
case PROP_FK_CONSTRAINT:
173
mg_canvas_fkconstraint_add_constraint (cc, g_value_get_pointer (value));
179
mg_canvas_fkconstraint_get_property (GObject *object,
184
MgCanvasFkconstraint *cc;
186
cc = MG_CANVAS_FKCONSTRAINT (object);
190
g_warning ("No such property!");
196
constraint_nullified_cb (MgDbConstraint *fkcons, MgCanvasFkconstraint *cc)
198
g_assert (g_slist_find (cc->priv->constraints, fkcons));
199
cc->priv->constraints = g_slist_remove (cc->priv->constraints, fkcons);
200
g_signal_handlers_disconnect_by_func (G_OBJECT (fkcons),
201
G_CALLBACK (constraint_nullified_cb), cc);
203
/* destroy itself if there are no more constraint left in the end */
204
if (!cc->priv->constraints)
205
gtk_object_destroy (GTK_OBJECT (cc));
213
entity_destroy_cb (MgCanvasEntity *entity, MgCanvasFkconstraint *cc)
215
gtk_object_destroy (GTK_OBJECT (cc));
219
static gboolean single_item_event_cb (GnomeCanvasItem *ci, GdkEvent *event, MgCanvasFkconstraint *cc);
220
static void entity_item_moved_cb (GnomeCanvasItem *entity, MgCanvasFkconstraint *cc);
223
* destroy any existing GnomeCanvasItem objects
226
clean_items (MgCanvasFkconstraint *cc)
228
if (cc->priv->fk_entity_item) {
229
g_signal_handlers_disconnect_by_func (G_OBJECT (cc->priv->fk_entity_item),
230
G_CALLBACK (entity_item_moved_cb), cc);
231
g_signal_handlers_disconnect_by_func (G_OBJECT (cc->priv->fk_entity_item),
232
G_CALLBACK (entity_destroy_cb), cc);
233
cc->priv->fk_entity_item = NULL;
236
if (cc->priv->ref_pk_entity_item) {
237
g_signal_handlers_disconnect_by_func (G_OBJECT (cc->priv->ref_pk_entity_item),
238
G_CALLBACK (entity_item_moved_cb), cc);
239
g_signal_handlers_disconnect_by_func (G_OBJECT (cc->priv->ref_pk_entity_item),
240
G_CALLBACK (entity_destroy_cb), cc);
241
cc->priv->ref_pk_entity_item = NULL;
244
/* remove all the GnomeCanvasItem objects */
245
while (GNOME_CANVAS_GROUP (cc)->item_list)
246
gtk_object_destroy (GTK_OBJECT (GNOME_CANVAS_GROUP (cc)->item_list->data));
250
/* structure to return shapes, being either points or a path definition */
252
GnomeCanvasPoints *points;
253
GnomeCanvasPathDef *path_def;
255
#define ANCHOR_SHAPE(x) ((AnchorShape*)(x))
257
static GSList *compute_anchor_shapes (MgCanvasEntity *fk_ent, MgCanvasEntity *ref_pk_ent, guint nb_anchors);
258
static void free_anchor_shapes (GSList *anchor_shapes);
260
* create new GnomeCanvasItem objects
262
* It is assumed that the list of FK constraints to render is coherent (that all the constraints are
263
* FK constraints, for the same table, referencing the same FK table).
266
create_items (MgCanvasFkconstraint *cc)
268
GnomeCanvasItem *item;
269
GSList *fklist = cc->priv->constraints, *list, *anchor_shapes, *list2;
270
MgDbConstraint *fkcons;
272
MgCanvasItem *entity_item;
273
MgCanvas *canvas = mg_canvas_item_get_canvas (MG_CANVAS_ITEM (cc));
275
gboolean user_constraint;
280
/* Analyse FK constraint */
281
fkcons = MG_DB_CONSTRAINT (fklist->data);
282
item = GNOME_CANVAS_ITEM (cc);
283
table = mg_db_constraint_get_table (fkcons);
284
entity_item = mg_canvas_get_item_for_object (canvas, MG_BASE (table));
285
g_return_if_fail (entity_item);
286
cc->priv->fk_entity_item = MG_CANVAS_ENTITY (entity_item);
287
g_signal_connect (G_OBJECT (entity_item), "moving",
288
G_CALLBACK (entity_item_moved_cb), cc);
289
g_signal_connect (G_OBJECT (entity_item), "moved",
290
G_CALLBACK (entity_item_moved_cb), cc);
291
g_signal_connect (G_OBJECT (entity_item), "shifted",
292
G_CALLBACK (entity_item_moved_cb), cc);
293
g_signal_connect (G_OBJECT (entity_item), "destroy",
294
G_CALLBACK (entity_destroy_cb), cc);
296
table = mg_db_constraint_fkey_get_ref_table (fkcons);
297
entity_item = mg_canvas_get_item_for_object (canvas, MG_BASE (table));
298
g_return_if_fail (entity_item);
299
cc->priv->ref_pk_entity_item = MG_CANVAS_ENTITY (entity_item);
300
g_signal_connect (G_OBJECT (entity_item), "moving",
301
G_CALLBACK (entity_item_moved_cb), cc);
302
g_signal_connect (G_OBJECT (entity_item), "moved",
303
G_CALLBACK (entity_item_moved_cb), cc);
304
g_signal_connect (G_OBJECT (entity_item), "shifted",
305
G_CALLBACK (entity_item_moved_cb), cc);
306
g_signal_connect (G_OBJECT (entity_item), "destroy",
307
G_CALLBACK (entity_destroy_cb), cc);
310
anchor_shapes = compute_anchor_shapes (cc->priv->fk_entity_item, cc->priv->ref_pk_entity_item,
311
g_slist_length (fklist));
312
list2 = anchor_shapes;
314
while (list && list2) {
315
AnchorShape *shape = ANCHOR_SHAPE (list2->data);
317
fkcons = MG_DB_CONSTRAINT (list->data);
318
g_object_get (G_OBJECT (fkcons), "user_constraint", &user_constraint, NULL);
320
style = GDK_LINE_ON_OFF_DASH;
322
style = GDK_LINE_SOLID;
325
item = gnome_canvas_item_new (GNOME_CANVAS_GROUP (cc),
326
GNOME_TYPE_CANVAS_LINE,
327
"points", shape->points,
328
"fill_color", "black",
330
"cap_style", GDK_CAP_ROUND,
332
"first_arrowhead", TRUE,
334
"arrow-shape-b", 12.,
338
g_object_set_data (G_OBJECT (item), "fkcons", fkcons);
339
g_signal_connect (G_OBJECT (item), "event",
340
G_CALLBACK (single_item_event_cb), cc);
342
if (shape->path_def) {
343
item = gnome_canvas_item_new (GNOME_CANVAS_GROUP (cc),
344
gnome_canvas_bpath_get_type(),
345
"bpath", shape->path_def,
346
"fill_color", "black",
348
"cap_style", GDK_CAP_ROUND,
350
g_object_set_data (G_OBJECT (item), "fkcons", fkcons);
351
g_signal_connect (G_OBJECT (item), "event",
352
G_CALLBACK (single_item_event_cb), cc);
355
list = g_slist_next (list);
356
list2 = g_slist_next (list2);
358
free_anchor_shapes (anchor_shapes);
361
static void popup_delete_cb (GtkMenuItem *mitem, MgCanvasFkconstraint *cc);
365
* item is for a single FK constraint
368
single_item_event_cb (GnomeCanvasItem *ci, GdkEvent *event, MgCanvasFkconstraint *cc)
370
MgDbConstraint *fkcons = g_object_get_data (G_OBJECT (ci), "fkcons");
371
gboolean highlight = FALSE, is_user_constraint = FALSE;
372
GtkWidget *menu, *entry;
373
gboolean done = FALSE;
374
GSList *list, *pairs;
376
switch (event->type) {
377
case GDK_ENTER_NOTIFY:
379
case GDK_LEAVE_NOTIFY:
380
pairs = mg_db_constraint_fkey_get_fields (fkcons);
383
MgDbConstraintFkeyPair *pair = MG_DB_CONSTRAINT_FK_PAIR (list->data);
384
MgCanvasField *field;
386
field = mg_canvas_entity_get_field_item (cc->priv->fk_entity_item,
387
MG_FIELD (pair->fkey));
388
mg_canvas_text_set_highlight (MG_CANVAS_TEXT (field), highlight);
389
field = mg_canvas_entity_get_field_item (cc->priv->ref_pk_entity_item,
390
MG_FIELD (pair->ref_pkey));
391
mg_canvas_text_set_highlight (MG_CANVAS_TEXT (field), highlight);
394
list = g_slist_next (list);
396
g_slist_free (pairs);
398
case GDK_BUTTON_PRESS:
399
menu = gtk_menu_new ();
400
entry = gtk_menu_item_new_with_label (_("Remove"));
401
g_object_get (G_OBJECT (fkcons), "user_constraint", &is_user_constraint, NULL);
402
gtk_widget_set_sensitive (entry, is_user_constraint);
403
g_object_set_data (G_OBJECT (entry), "fkcons", fkcons);
404
g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (popup_delete_cb), cc);
405
gtk_menu_append (GTK_MENU (menu), entry);
406
gtk_widget_show (entry);
407
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
408
NULL, NULL, ((GdkEventButton *)event)->button,
409
((GdkEventButton *)event)->time);
421
popup_delete_cb (GtkMenuItem *mitem, MgCanvasFkconstraint *cc)
423
MgDbConstraint *fkcons = g_object_get_data (G_OBJECT (mitem), "fkcons");
424
gboolean is_user_constraint;
426
g_object_get (G_OBJECT (fkcons), "user_constraint", &is_user_constraint, NULL);
427
if (is_user_constraint)
428
mg_base_nullify (MG_BASE (fkcons));
432
entity_item_moved_cb (GnomeCanvasItem *entity, MgCanvasFkconstraint *cc)
440
compute_intersect_rect_line (gdouble rectx1, gdouble recty1, gdouble rectx2, gdouble recty2,
441
gdouble P1x, gdouble P1y, gdouble P2x, gdouble P2y,
442
gdouble *R1x, gdouble *R1y, gdouble *R2x, gdouble *R2y);
445
* mg_canvas_fkconstraint_add_constraint
449
* Add @fkcons to the list of displayed constraints
452
mg_canvas_fkconstraint_add_constraint (MgCanvasFkconstraint *cc, MgDbConstraint *fkcons)
454
g_return_if_fail (cc && IS_MG_CANVAS_FKCONSTRAINT (cc));
455
g_return_if_fail (cc->priv);
456
g_return_if_fail (fkcons && IS_MG_DB_CONSTRAINT (fkcons));
457
g_return_if_fail (mg_db_constraint_get_constraint_type (MG_DB_CONSTRAINT (fkcons)) ==
458
CONSTRAINT_FOREIGN_KEY);
460
if (g_slist_find (cc->priv->constraints, fkcons))
463
if (cc->priv->constraints) {
464
/* there are already some FK constraints there, so test that the new one is
465
* compatible with the existing ones*/
469
cc->priv->constraints = g_slist_append (cc->priv->constraints, fkcons);
470
g_signal_connect (G_OBJECT (fkcons), "nullified",
471
G_CALLBACK (constraint_nullified_cb), cc);
478
* Computes the points' coordinates of the line going from
479
* @ref_pk_ent to @fk_ent (which are themselves rectangles)
481
* Returns a list of AnchorShape structures, use free_anchor_shapes() to free it.
484
compute_anchor_shapes (MgCanvasEntity *fk_ent, MgCanvasEntity *ref_pk_ent, guint nb_anchors)
486
GSList *retval = NULL;
488
gdouble fx1, fy1, fx2, fy2; /* FK entity item (bounds) */
489
gdouble rx1, ry1, rx2, ry2; /* REF PK entity item (bounds) */
491
gdouble rcx, rcy; /* center of ref_pk entity item */
494
gdouble rux, ruy; /* current ref_pk point for the arrow line */
495
gdouble dx, dy; /* increments to compute the new ref_pk point for the arrow line */
497
g_return_val_if_fail (nb_anchors > 0, NULL);
499
gnome_canvas_item_get_bounds (GNOME_CANVAS_ITEM (fk_ent), &fx1, &fy1, &fx2, &fy2);
500
gnome_canvas_item_get_bounds (GNOME_CANVAS_ITEM (ref_pk_ent), &rx1, &ry1, &rx2, &ry2);
502
/* compute the cx, cy, dx and dy values */
503
rcx = (rx1 + rx2) / 2.;
504
rcy = (ry1 + ry2) / 2.;
505
cx = (fx1 + fx2) / 2.;
506
cy = (fy1 + fy2) / 2.;
512
for (i = 0; i < nb_anchors; i++) {
513
AnchorShape *shape = g_new0 (AnchorShape, 1);
516
- detect tables overlapping
518
if ((rcx == cx) && (rcy == cy)) {
519
/* tables have the same center (includes when they are equal) */
521
GnomeCanvasPoints *ap, *points;
523
points = gnome_canvas_points_new (4);
524
ap = gnome_canvas_points_new (4);
526
Dy = (ry2 - ry1) / 2. / (gdouble ) (nb_anchors + 1) * (gdouble) (i + 1);
527
Dx = (rx2 - rx1) * (0.8 + 0.1 * i);
528
g_assert (compute_intersect_rect_line (rx1, ry1, rx2, ry2,
529
cx, cy, cx + Dx, cy - Dy,
530
&(ap->coords[0]), &(ap->coords[1]),
531
&(ap->coords[2]), &(ap->coords[3])));
533
if (ap->coords[0] > ap->coords[2]) {
534
points->coords[0] = ap->coords[0];
535
points->coords[1] = ap->coords[1];
538
points->coords[0] = ap->coords[2];
539
points->coords[1] = ap->coords[3];
542
points->coords[2] = cx + Dx;
543
points->coords[3] = cy - Dy;
545
Dy = (fy2 - fy1) / 2. / (gdouble ) (nb_anchors + 1) * (gdouble) (i + 1);
546
Dx = (fx2 - fx1) * (0.8 + 0.1 * i);
547
points->coords[4] = cx + Dx;
548
points->coords[5] = cy + Dy;
550
g_assert (compute_intersect_rect_line (fx1, fy1, fx2, fy2,
551
cx, cy, cx + Dx, cy + Dy,
552
&(ap->coords[0]), &(ap->coords[1]),
553
&(ap->coords[2]), &(ap->coords[3])));
555
if (ap->coords[0] > ap->coords[2]) {
556
points->coords[6] = ap->coords[0];
557
points->coords[7] = ap->coords[1];
560
points->coords[6] = ap->coords[2];
561
points->coords[7] = ap->coords[3];
564
shape->points = points;
565
gnome_canvas_points_free (ap);
567
/* GnomeCanvasPathDef *path_def; */
569
/* path_def = gnome_canvas_path_def_new(); */
571
/* gnome_canvas_path_def_moveto(path_def, 500.0, 175.0); */
572
/* gnome_canvas_path_def_curveto(path_def, 550.0, 175.0, 550.0, 275.0, 500.0, 275.0); */
573
/* shape->path_def = path_def; */
577
GnomeCanvasPoints *ap, *points;
579
points = gnome_canvas_points_new (2);
580
ap = gnome_canvas_points_new (4);
582
if (nb_anchors > 1) {
583
if ((dx == 0) && (dy == 0)) {
584
/* compute perpendicular to D={(rcx, rcy), (cx, cy)} */
585
gdouble vx = (rcx - cx), vy = (rcy - cy);
592
/* compute intersect of ref_pkey rectangle and D=[vx, vy] passing at (rcx, rcy) */
593
g_assert (compute_intersect_rect_line (rx1, ry1, rx2, ry2,
594
rcx, rcy, rcx + vx, rcy + vy,
595
&(ap->coords[0]), &(ap->coords[1]),
596
&(ap->coords[2]), &(ap->coords[3])));
597
dx = (ap->coords[2] - ap->coords[0]) / (gdouble) (nb_anchors + 1);
598
dy = (ap->coords[3] - ap->coords[1]) / (gdouble) (nb_anchors + 1);
607
/* compute the 4 intersection points */
608
g_assert (compute_intersect_rect_line (rx1, ry1, rx2, ry2,
610
&(ap->coords[0]), &(ap->coords[1]),
611
&(ap->coords[2]), &(ap->coords[3])));
612
g_assert (compute_intersect_rect_line (fx1, fy1, fx2, fy2,
614
&(ap->coords[4]), &(ap->coords[5]),
615
&(ap->coords[6]), &(ap->coords[7])));
617
/* choosing between point coords(0,1) and coords(2,3) */
618
if (((ap->coords[0] - ap->coords[4]) * (ap->coords[0] - ap->coords[4]) +
619
(ap->coords[1] - ap->coords[5]) * (ap->coords[1] - ap->coords[5])) <
620
((ap->coords[2] - ap->coords[4]) * (ap->coords[2] - ap->coords[4]) +
621
(ap->coords[3] - ap->coords[5]) * (ap->coords[3] - ap->coords[5]))) {
622
points->coords[0] = ap->coords[0];
623
points->coords[1] = ap->coords[1];
626
points->coords[0] = ap->coords[2];
627
points->coords[1] = ap->coords[3];
630
/* choosing between point coords(4,5) and coords(6,7) */
631
if (((points->coords[0] - ap->coords[4]) * (points->coords[0] - ap->coords[4]) +
632
(points->coords[1] - ap->coords[5]) * (points->coords[1] - ap->coords[5])) <
633
((points->coords[0] - ap->coords[6]) * (points->coords[0] - ap->coords[6]) +
634
(points->coords[1] - ap->coords[7]) * (points->coords[1] - ap->coords[7]))) {
635
points->coords[2] = ap->coords[4];
636
points->coords[3] = ap->coords[5];
639
points->coords[2] = ap->coords[6];
640
points->coords[3] = ap->coords[7];
643
shape->points = points;
644
gnome_canvas_points_free (ap);
647
retval = g_slist_append (retval, shape);
654
* Free the list of points
657
free_anchor_shapes (GSList *anchor_shapes)
659
GSList *list = anchor_shapes;
665
AnchorShape *shape = ANCHOR_SHAPE (list->data);
667
gnome_canvas_points_free (shape->points);
669
gnome_canvas_path_def_unref (shape->path_def);
671
list = g_slist_next (list);
673
g_slist_free (anchor_shapes);
677
* Computes the points of intersection between a rectangle (defined by the first 2 points)
678
* and a line (defined by the next 2 points).
680
* The result is returned in place of the line's point definition
696
* Returns: TRUE if the line crosses the rectangle, and FALSE if it misses it.
699
compute_intersect_rect_line (gdouble rectx1, gdouble recty1, gdouble rectx2, gdouble recty2,
700
gdouble P1x, gdouble P1y, gdouble P2x, gdouble P2y,
701
gdouble *R1x, gdouble *R1y, gdouble *R2x, gdouble *R2y)
703
gboolean retval = FALSE;
704
gboolean rotated = FALSE;
705
gdouble a=0.; /* line slope y = a x + b */
706
gdouble b; /* line offset y = a x + b */
709
gdouble ptsx[4]; /* points' X coordinate: 0 for intersect with D1, 1 for D2,... */
710
gdouble ptsy[4]; /* points' Y coordinate */
712
g_return_val_if_fail ((rectx1 != rectx2) || (recty1 != recty2), FALSE);
713
g_return_val_if_fail ((rectx1 < rectx2) && (recty1 < recty2), FALSE);
714
g_return_val_if_fail ((P1x != P2x) || (P1y != P2y), FALSE);
716
/* rotate the coordinates to invert X and Y to avoid rounding problems ? */
718
a = (P1y - P2y) / (P1x - P2x);
719
if ((P1x == P2x) || (fabs (a) > 1)) {
722
tmp = rectx1; rectx1 = recty1; recty1 = tmp;
723
tmp = rectx2; rectx2 = recty2; recty2 = tmp;
724
tmp = P1x; P1x = P1y; P1y = tmp;
725
tmp = P2x; P2x = P2y; P2y = tmp;
726
a = (P1y - P2y) / (P1x - P2x);
729
/* here we have (P1x != P2x), non vertical line */
733
/* horizontal line */
735
if ((b <= recty2) && (b >= recty1)) {
737
*R1x = rectx1 - offset; *R1y = b;
738
*R2x = rectx2 + offset; *R2y = b;
742
gdouble retx[2] = {0., 0.};
743
gdouble rety[2] = {0., 0.};
746
/* non horizontal and non vertical line */
748
ptsy[0] = recty1 - offset;
749
ptsx[0] = (recty1 - b) / a;
752
ptsy[1] = recty2 + offset;
753
ptsx[1] = (recty2 - b) / a;
756
ptsx[2] = rectx1 - offset;
757
ptsy[2] = a * rectx1 + b;
760
ptsx[3] = rectx2 + offset;
761
ptsy[3] = a * rectx2 + b;
763
if ((ptsx[0] >= rectx1) && (ptsx[0] <= rectx2)) {
765
retx[i] = ptsx[0]; rety[i] = ptsy[0];
768
if ((ptsx[1] >= rectx1) && (ptsx[1] <= rectx2)) {
770
retx[i] = ptsx[1]; rety[i] = ptsy[1];
773
if ((i<2) && (ptsy[2] >= recty1) && (ptsy[2] <= recty2)) {
775
retx[i] = ptsx[2]; rety[i] = ptsy[2];
778
if ((i<2) && (ptsy[3] >= recty1) && (ptsy[3] <= recty2)) {
780
retx[i] = ptsx[3]; rety[i] = ptsy[3];
785
g_assert (i == 2); /* wee need 2 points! */
786
*R1x = retx[0]; *R1y = rety[0];
787
*R2x = retx[1]; *R2y = rety[1];
791
if (retval && rotated) {
795
tmp = *R1x; *R1x = *R1y; *R1y = tmp;
796
tmp = *R2x; *R2x = *R2y; *R2y = tmp;