2006-12-05 David Lodge <dave@cirt.net>
[dia.git] / objects / ER / participation.c
blob18d1f3415681a41d427a46e7d2fce0383d060b97
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 /* DO NOT USE THIS OBJECT AS A BASIS FOR A NEW OBJECT. */
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <assert.h>
26 #include <math.h>
27 #include <string.h>
29 #include "intl.h"
30 #include "object.h"
31 #include "orth_conn.h"
32 #include "diarenderer.h"
33 #include "attributes.h"
34 #include "arrows.h"
35 #include "properties.h"
37 #include "pixmaps/participation.xpm"
39 typedef struct _Participation Participation;
41 struct _Participation {
42 OrthConn orth;
44 gboolean total;
48 #define PARTICIPATION_WIDTH 0.1
49 #define PARTICIPATION_DASHLEN 0.4
50 #define PARTICIPATION_FONTHEIGHT 0.8
51 #define TOTAL_SEPARATION 0.25
53 static real participation_distance_from(Participation *dep, Point *point);
54 static void participation_select(Participation *dep, Point *clicked_point,
55 DiaRenderer *interactive_renderer);
56 static ObjectChange* participation_move_handle(Participation *dep, Handle *handle,
57 Point *to, ConnectionPoint *cp,
58 HandleMoveReason reason, ModifierKeys modifiers);
59 static ObjectChange* participation_move(Participation *dep, Point *to);
60 static void participation_draw(Participation *dep, DiaRenderer *renderer);
61 static DiaObject *participation_create(Point *startpoint,
62 void *user_data,
63 Handle **handle1,
64 Handle **handle2);
65 static DiaObject *participation_copy(Participation *dep);
66 static void participation_save(Participation *dep, ObjectNode obj_node,
67 const char *filename);
68 static DiaObject *participation_load(ObjectNode obj_node, int version,
69 const char *filename);
70 static void participation_update_data(Participation *dep);
71 static PropDescription *
72 participation_describe_props(Participation *participation);
73 static void
74 participation_get_props(Participation *participation, GPtrArray *props);
75 static void
76 participation_set_props(Participation *participation, GPtrArray *props);
77 static DiaMenu *participation_get_object_menu(Participation *participation,
78 Point *clickedpoint);
80 static ObjectTypeOps participation_type_ops =
82 (CreateFunc) participation_create,
83 (LoadFunc) participation_load,
84 (SaveFunc) participation_save
87 DiaObjectType participation_type =
89 "ER - Participation", /* name */
90 /* Version 0 had no autorouting and so shouldn't have it set by default. */
91 1, /* version */
92 (char **) participation_xpm, /* pixmap */
94 &participation_type_ops /* ops */
97 static ObjectOps participation_ops = {
98 (DestroyFunc) orthconn_destroy,
99 (DrawFunc) participation_draw,
100 (DistanceFunc) participation_distance_from,
101 (SelectFunc) participation_select,
102 (CopyFunc) participation_copy,
103 (MoveFunc) participation_move,
104 (MoveHandleFunc) participation_move_handle,
105 (GetPropertiesFunc) object_create_props_dialog,
106 (ApplyPropertiesFunc) object_apply_props_from_dialog,
107 (ObjectMenuFunc) participation_get_object_menu,
108 (DescribePropsFunc) participation_describe_props,
109 (GetPropsFunc) participation_get_props,
110 (SetPropsFunc) participation_set_props
113 static PropDescription participation_props[] = {
114 ORTHCONN_COMMON_PROPERTIES,
115 { "total", PROP_TYPE_BOOL, PROP_FLAG_VISIBLE,
116 N_("Total:"), NULL, NULL },
117 PROP_DESC_END
120 static PropDescription *
121 participation_describe_props(Participation *participation)
123 if (participation_props[0].quark == 0)
124 prop_desc_list_calculate_quarks(participation_props);
125 return participation_props;
128 static PropOffset participation_offsets[] = {
129 ORTHCONN_COMMON_PROPERTIES_OFFSETS,
130 { "total", PROP_TYPE_BOOL, offsetof(Participation, total) },
131 { NULL, 0, 0}
135 static void
136 participation_get_props(Participation *participation, GPtrArray *props)
138 object_get_props_from_offsets(&participation->orth.object,
139 participation_offsets, props);
142 static void
143 participation_set_props(Participation *participation, GPtrArray *props)
145 object_set_props_from_offsets(&participation->orth.object,
146 participation_offsets, props);
147 participation_update_data(participation);
151 static real
152 participation_distance_from(Participation *participation, Point *point)
154 OrthConn *orth = &participation->orth;
155 return orthconn_distance_from(orth, point, PARTICIPATION_WIDTH);
158 static void
159 participation_select(Participation *participation, Point *clicked_point,
160 DiaRenderer *interactive_renderer)
162 orthconn_update_data(&participation->orth);
165 static ObjectChange*
166 participation_move_handle(Participation *participation, Handle *handle,
167 Point *to, ConnectionPoint *cp,
168 HandleMoveReason reason, ModifierKeys modifiers)
170 ObjectChange *change;
171 assert(participation!=NULL);
172 assert(handle!=NULL);
173 assert(to!=NULL);
175 change = orthconn_move_handle(&participation->orth, handle, to, cp,
176 reason, modifiers);
177 participation_update_data(participation);
179 return change;
182 static ObjectChange*
183 participation_move(Participation *participation, Point *to)
185 ObjectChange *change;
187 change = orthconn_move(&participation->orth, to);
188 participation_update_data(participation);
190 return change;
193 static void
194 participation_draw(Participation *participation, DiaRenderer *renderer)
196 DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
197 OrthConn *orth = &participation->orth;
198 Point *points;
199 Point *left_points;
200 Point *right_points;
201 int i, n;
202 real last_left, last_right;
204 points = &orth->points[0];
205 n = orth->numpoints;
207 last_left = 0.0;
208 last_right = 0.0;
210 renderer_ops->set_linewidth(renderer, PARTICIPATION_WIDTH);
211 renderer_ops->set_linestyle(renderer, LINESTYLE_SOLID);
212 renderer_ops->set_linejoin(renderer, LINEJOIN_MITER);
213 renderer_ops->set_linecaps(renderer, LINECAPS_BUTT);
215 if (participation->total) {
216 left_points = g_new0(Point, n);
217 right_points = g_new0(Point, n);
218 for(i = 0; i < n - 1; i++) {
219 if(orth->orientation[i] == HORIZONTAL) { /* HORIZONTAL */
220 if (points[i].x < points[i+1].x) { /* RIGHT */
221 left_points[i].x = points[i].x + last_left;
222 left_points[i].y = points[i].y - TOTAL_SEPARATION / 2.0;
223 last_left = - TOTAL_SEPARATION/2.0;
224 right_points[i].x = points[i].x + last_right;
225 right_points[i].y = points[i].y + TOTAL_SEPARATION / 2.0;
226 last_right = TOTAL_SEPARATION/2.0;
227 } else { /* LEFT */
228 left_points[i].x = points[i].x + last_left;
229 left_points[i].y = points[i].y + TOTAL_SEPARATION / 2.0;
230 last_left = TOTAL_SEPARATION/2.0;
231 right_points[i].x = points[i].x + last_right;
232 right_points[i].y = points[i].y - TOTAL_SEPARATION / 2.0;
233 last_right = - TOTAL_SEPARATION/2.0;
235 } else { /* VERTICAL */
236 if (points[i].y < points[i+1].y) { /* DOWN */
237 left_points[i].x = points[i].x + TOTAL_SEPARATION / 2.0;
238 left_points[i].y = points[i].y + last_left;
239 last_left = TOTAL_SEPARATION/2.0;
240 right_points[i].x = points[i].x - TOTAL_SEPARATION / 2.0;
241 right_points[i].y = points[i].y + last_right;
242 last_right = - TOTAL_SEPARATION/2.0;
243 } else { /* UP */
244 left_points[i].x = points[i].x - TOTAL_SEPARATION / 2.0;
245 left_points[i].y = points[i].y + last_left;
246 last_left = - TOTAL_SEPARATION/2.0;
247 right_points[i].x = points[i].x + TOTAL_SEPARATION / 2.0;
248 right_points[i].y = points[i].y + last_right;
249 last_right = TOTAL_SEPARATION/2.0;
253 if(orth->orientation[i-1] == HORIZONTAL) { /* HORIZONTAL */
254 left_points[i].x = points[i].x;
255 left_points[i].y = points[i].y + last_left;
256 right_points[i].x = points[i].x;
257 right_points[i].y = points[i].y + last_right;
258 } else { /* VERTICAL */
259 left_points[i].x = points[i].x + last_left;
260 left_points[i].y = points[i].y;
261 right_points[i].x = points[i].x + last_right;
262 right_points[i].y = points[i].y;
265 renderer_ops->draw_polyline(renderer, left_points, n, &color_black);
266 renderer_ops->draw_polyline(renderer, right_points, n, &color_black);
267 g_free(left_points);
268 g_free(right_points);
269 } else {
270 renderer_ops->draw_polyline(renderer, points, n, &color_black);
274 static void
275 participation_update_data(Participation *participation)
277 OrthConn *orth = &participation->orth;
278 PolyBBExtras *extra = &orth->extra_spacing;
279 real extra_width;
281 orthconn_update_data(orth);
283 if (participation->total) {
284 extra_width = TOTAL_SEPARATION/2.0;
285 } else {
286 extra_width = 0.0;
288 extra->middle_trans =
289 extra->start_trans =
290 extra->end_trans =
291 extra->start_long =
292 extra->end_long = PARTICIPATION_WIDTH/2.0 + extra_width;
294 orthconn_update_boundingbox(orth);
297 static DiaObject *
298 participation_create(Point *startpoint,
299 void *user_data,
300 Handle **handle1,
301 Handle **handle2)
303 Participation *participation;
304 OrthConn *orth;
305 DiaObject *obj;
307 participation = g_malloc0(sizeof(Participation));
308 orth = &participation->orth;
309 obj = &orth->object;
311 obj->type = &participation_type;
313 obj->ops = &participation_ops;
315 orthconn_init(orth, startpoint);
317 participation_update_data(participation);
319 participation->total = FALSE;
321 *handle1 = orth->handles[0];
322 *handle2 = orth->handles[orth->numpoints-2];
324 return &participation->orth.object;
327 static DiaObject *
328 participation_copy(Participation *participation)
330 Participation *newparticipation;
331 OrthConn *orth, *neworth;
332 DiaObject *newobj;
334 orth = &participation->orth;
336 newparticipation = g_malloc0(sizeof(Participation));
337 neworth = &newparticipation->orth;
338 newobj = &neworth->object;
340 orthconn_copy(orth, neworth);
342 newparticipation->total = participation->total;
344 participation_update_data(newparticipation);
346 return &newparticipation->orth.object;
350 static void
351 participation_save(Participation *participation, ObjectNode obj_node,
352 const char *filename)
354 orthconn_save(&participation->orth, obj_node);
356 data_add_boolean(new_attribute(obj_node, "total"),
357 participation->total);
360 static DiaObject *
361 participation_load(ObjectNode obj_node, int version, const char *filename)
363 AttributeNode attr;
364 Participation *participation;
365 OrthConn *orth;
366 DiaObject *obj;
368 participation = g_new0(Participation, 1);
370 orth = &participation->orth;
371 obj = &orth->object;
373 obj->type = &participation_type;
374 obj->ops = &participation_ops;
376 orthconn_load(orth, obj_node);
378 attr = object_find_attribute(obj_node, "total");
379 if (attr != NULL)
380 participation->total = data_boolean(attribute_first_data(attr));
382 participation_update_data(participation);
384 return &participation->orth.object;
387 static ObjectChange *
388 participation_add_segment_callback(DiaObject *obj, Point *clicked, gpointer data)
390 ObjectChange *change;
391 change = orthconn_add_segment((OrthConn *)obj, clicked);
392 participation_update_data((Participation *)obj);
393 return change;
396 static ObjectChange *
397 participation_delete_segment_callback(DiaObject *obj, Point *clicked, gpointer data)
399 ObjectChange *change;
400 change = orthconn_delete_segment((OrthConn *)obj, clicked);
401 participation_update_data((Participation *)obj);
402 return change;
405 static DiaMenuItem object_menu_items[] = {
406 { N_("Add segment"), participation_add_segment_callback, NULL, 1 },
407 { N_("Delete segment"), participation_delete_segment_callback, NULL, 1 },
408 ORTHCONN_COMMON_MENUS,
411 static DiaMenu object_menu = {
412 "Participation",
413 sizeof(object_menu_items)/sizeof(DiaMenuItem),
414 object_menu_items,
415 NULL
418 static DiaMenu *
419 participation_get_object_menu(Participation *participation, Point *clickedpoint)
421 OrthConn *orth;
423 orth = &participation->orth;
424 /* Set entries sensitive/selected etc here */
425 object_menu_items[0].active = orthconn_can_add_segment(orth, clickedpoint);
426 object_menu_items[1].active = orthconn_can_delete_segment(orth, clickedpoint);
427 orthconn_update_object_menu(orth, clickedpoint, &object_menu_items[2]);
428 return &object_menu;