1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1999 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.
29 #include "poly_conn.h"
30 #include "connectionpoint.h"
32 #include "attributes.h"
36 #include "properties.h"
40 #include "pixmaps/polyline.xpm"
42 #define DEFAULT_WIDTH 0.15
44 typedef struct _Polyline
{
51 Arrow start_arrow
, end_arrow
;
55 static void polyline_move_handle(Polyline
*polyline
, Handle
*handle
,
56 Point
*to
, HandleMoveReason reason
, ModifierKeys modifiers
);
57 static void polyline_move(Polyline
*polyline
, Point
*to
);
58 static void polyline_select(Polyline
*polyline
, Point
*clicked_point
,
59 Renderer
*interactive_renderer
);
60 static void polyline_draw(Polyline
*polyline
, Renderer
*renderer
);
61 static Object
*polyline_create(Point
*startpoint
,
65 static real
polyline_distance_from(Polyline
*polyline
, Point
*point
);
66 static void polyline_update_data(Polyline
*polyline
);
67 static void polyline_destroy(Polyline
*polyline
);
68 static Object
*polyline_copy(Polyline
*polyline
);
70 static PropDescription
*polyline_describe_props(Polyline
*polyline
);
71 static void polyline_get_props(Polyline
*polyline
, GPtrArray
*props
);
72 static void polyline_set_props(Polyline
*polyline
, GPtrArray
*props
);
74 static void polyline_save(Polyline
*polyline
, ObjectNode obj_node
,
75 const char *filename
);
76 static Object
*polyline_load(ObjectNode obj_node
, int version
,
77 const char *filename
);
78 static DiaMenu
*polyline_get_object_menu(Polyline
*polyline
, Point
*clickedpoint
);
80 static ObjectTypeOps polyline_type_ops
=
82 (CreateFunc
)polyline_create
, /* create */
83 (LoadFunc
) polyline_load
, /* load */
84 (SaveFunc
) polyline_save
, /* save */
85 (GetDefaultsFunc
) NULL
/*polyline_get_defaults*/,
86 (ApplyDefaultsFunc
) NULL
/*polyline_apply_defaults*/
89 static ObjectType polyline_type
=
91 "Standard - PolyLine", /* name */
93 (char **) polyline_xpm
, /* pixmap */
95 &polyline_type_ops
/* ops */
98 ObjectType
*_polyline_type
= (ObjectType
*) &polyline_type
;
101 static ObjectOps polyline_ops
= {
102 (DestroyFunc
) polyline_destroy
,
103 (DrawFunc
) polyline_draw
,
104 (DistanceFunc
) polyline_distance_from
,
105 (SelectFunc
) polyline_select
,
106 (CopyFunc
) polyline_copy
,
107 (MoveFunc
) polyline_move
,
108 (MoveHandleFunc
) polyline_move_handle
,
109 (GetPropertiesFunc
) object_create_props_dialog
,
110 (ApplyPropertiesFunc
) object_apply_props_from_dialog
,
111 (ObjectMenuFunc
) polyline_get_object_menu
,
112 (DescribePropsFunc
) polyline_describe_props
,
113 (GetPropsFunc
) polyline_get_props
,
114 (SetPropsFunc
) polyline_set_props
,
117 static PropDescription polyline_props
[] = {
118 OBJECT_COMMON_PROPERTIES
,
120 PROP_STD_LINE_COLOUR
,
122 PROP_STD_START_ARROW
,
127 static PropDescription
*
128 polyline_describe_props(Polyline
*polyline
)
130 if (polyline_props
[0].quark
== 0)
131 prop_desc_list_calculate_quarks(polyline_props
);
132 return polyline_props
;
135 static PropOffset polyline_offsets
[] = {
136 OBJECT_COMMON_PROPERTIES_OFFSETS
,
137 { "line_width", PROP_TYPE_REAL
, offsetof(Polyline
, line_width
) },
138 { "line_colour", PROP_TYPE_COLOUR
, offsetof(Polyline
, line_color
) },
139 { "line_style", PROP_TYPE_LINESTYLE
,
140 offsetof(Polyline
, line_style
), offsetof(Polyline
, dashlength
) },
141 { "start_arrow", PROP_TYPE_ARROW
, offsetof(Polyline
, start_arrow
) },
142 { "end_arrow", PROP_TYPE_ARROW
, offsetof(Polyline
, end_arrow
) },
147 polyline_get_props(Polyline
*polyline
, GPtrArray
*props
)
149 object_get_props_from_offsets(&polyline
->poly
.object
, polyline_offsets
,
154 polyline_set_props(Polyline
*polyline
, GPtrArray
*props
)
156 object_set_props_from_offsets(&polyline
->poly
.object
, polyline_offsets
,
158 polyline_update_data(polyline
);
162 polyline_distance_from(Polyline
*polyline
, Point
*point
)
164 PolyConn
*poly
= &polyline
->poly
;
165 return polyconn_distance_from(poly
, point
, polyline
->line_width
);
168 static Handle
*polyline_closest_handle(Polyline
*polyline
, Point
*point
) {
169 return polyconn_closest_handle(&polyline
->poly
, point
);
172 static int polyline_closest_segment(Polyline
*polyline
, Point
*point
) {
173 PolyConn
*poly
= &polyline
->poly
;
174 return polyconn_closest_segment(poly
, point
, polyline
->line_width
);
178 polyline_select(Polyline
*polyline
, Point
*clicked_point
,
179 Renderer
*interactive_renderer
)
181 polyconn_update_data(&polyline
->poly
);
185 polyline_move_handle(Polyline
*polyline
, Handle
*handle
,
186 Point
*to
, HandleMoveReason reason
, ModifierKeys modifiers
)
188 assert(polyline
!=NULL
);
189 assert(handle
!=NULL
);
192 polyconn_move_handle(&polyline
->poly
, handle
, to
, reason
);
193 polyline_update_data(polyline
);
198 polyline_move(Polyline
*polyline
, Point
*to
)
200 polyconn_move(&polyline
->poly
, to
);
201 polyline_update_data(polyline
);
205 polyline_draw(Polyline
*polyline
, Renderer
*renderer
)
207 PolyConn
*poly
= &polyline
->poly
;
211 points
= &poly
->points
[0];
214 renderer
->ops
->set_linewidth(renderer
, polyline
->line_width
);
215 renderer
->ops
->set_linestyle(renderer
, polyline
->line_style
);
216 renderer
->ops
->set_dashlength(renderer
, polyline
->dashlength
);
217 renderer
->ops
->set_linejoin(renderer
, LINEJOIN_MITER
);
218 renderer
->ops
->set_linecaps(renderer
, LINECAPS_BUTT
);
220 renderer
->ops
->draw_polyline(renderer
, points
, n
, &polyline
->line_color
);
222 if (polyline
->start_arrow
.type
!= ARROW_NONE
) {
223 arrow_draw(renderer
, polyline
->start_arrow
.type
,
224 &points
[0], &points
[1],
225 polyline
->start_arrow
.length
, polyline
->start_arrow
.width
,
226 polyline
->line_width
,
227 &polyline
->line_color
, &color_white
);
229 if (polyline
->end_arrow
.type
!= ARROW_NONE
) {
230 arrow_draw(renderer
, polyline
->end_arrow
.type
,
231 &points
[n
-1], &points
[n
-2],
232 polyline
->end_arrow
.length
, polyline
->end_arrow
.width
,
233 polyline
->line_width
,
234 &polyline
->line_color
, &color_white
);
238 /** user_data is a struct polyline_create_data, containing an array of
240 If user_data is NULL, the startpoint is used and a 1x1 line is created.
241 Otherwise, the startpoint is ignored.
244 polyline_create(Point
*startpoint
,
252 Point defaultlen
= { 1.0, 1.0 };
254 /*polyline_init_defaults();*/
255 polyline
= g_malloc0(sizeof(Polyline
));
256 poly
= &polyline
->poly
;
259 obj
->type
= &polyline_type
;
260 obj
->ops
= &polyline_ops
;
262 if (user_data
== NULL
) {
263 polyconn_init(poly
, 2);
265 poly
->points
[0] = *startpoint
;
266 poly
->points
[1] = *startpoint
;
268 point_add(&poly
->points
[1], &defaultlen
);
270 *handle1
= poly
->object
.handles
[0];
271 *handle2
= poly
->object
.handles
[1];
273 PolylineCreateData
*pcd
= (PolylineCreateData
*)user_data
;
275 polyconn_init(poly
, pcd
->num_points
);
277 /* Handles are set up by polyconn_init and polyconn_update_data */
278 polyconn_set_points(poly
, pcd
->num_points
, pcd
->points
);
280 *handle1
= poly
->object
.handles
[0];
281 *handle2
= poly
->object
.handles
[pcd
->num_points
-1];
284 polyline_update_data(polyline
);
286 polyline
->line_width
= attributes_get_default_linewidth();
287 polyline
->line_color
= attributes_get_foreground();
288 attributes_get_default_line_style(&polyline
->line_style
,
289 &polyline
->dashlength
);
290 polyline
->start_arrow
= attributes_get_default_start_arrow();
291 polyline
->end_arrow
= attributes_get_default_end_arrow();
293 return &polyline
->poly
.object
;
297 polyline_destroy(Polyline
*polyline
)
299 polyconn_destroy(&polyline
->poly
);
303 polyline_copy(Polyline
*polyline
)
305 Polyline
*newpolyline
;
306 PolyConn
*poly
, *newpoly
;
309 poly
= &polyline
->poly
;
311 newpolyline
= g_malloc0(sizeof(Polyline
));
312 newpoly
= &newpolyline
->poly
;
313 newobj
= &newpoly
->object
;
315 polyconn_copy(poly
, newpoly
);
317 newpolyline
->line_color
= polyline
->line_color
;
318 newpolyline
->line_width
= polyline
->line_width
;
319 newpolyline
->line_style
= polyline
->line_style
;
320 newpolyline
->dashlength
= polyline
->dashlength
;
321 newpolyline
->start_arrow
= polyline
->start_arrow
;
322 newpolyline
->end_arrow
= polyline
->end_arrow
;
324 return &newpolyline
->poly
.object
;
328 polyline_update_data(Polyline
*polyline
)
330 PolyConn
*poly
= &polyline
->poly
;
331 Object
*obj
= &poly
->object
;
332 PolyBBExtras
*extra
= &poly
->extra_spacing
;
334 polyconn_update_data(&polyline
->poly
);
336 extra
->start_trans
= (polyline
->line_width
/ 2.0);
337 extra
->end_trans
= (polyline
->line_width
/ 2.0);
338 extra
->middle_trans
= (polyline
->line_width
/ 2.0);
340 if (polyline
->start_arrow
.type
!= ARROW_NONE
)
341 extra
->start_trans
= MAX(extra
->start_trans
,polyline
->start_arrow
.width
);
342 if (polyline
->end_arrow
.type
!= ARROW_NONE
)
343 extra
->end_trans
= MAX(extra
->end_trans
,polyline
->end_arrow
.width
);
345 extra
->start_long
= (polyline
->line_width
/ 2.0);
346 extra
->end_long
= (polyline
->line_width
/ 2.0);
348 polyconn_update_boundingbox(poly
);
350 obj
->position
= poly
->points
[0];
354 polyline_save(Polyline
*polyline
, ObjectNode obj_node
,
355 const char *filename
)
357 polyconn_save(&polyline
->poly
, obj_node
);
359 if (!color_equals(&polyline
->line_color
, &color_black
))
360 data_add_color(new_attribute(obj_node
, "line_color"),
361 &polyline
->line_color
);
363 if (polyline
->line_width
!= 0.1)
364 data_add_real(new_attribute(obj_node
, "line_width"),
365 polyline
->line_width
);
367 if (polyline
->line_style
!= LINESTYLE_SOLID
)
368 data_add_enum(new_attribute(obj_node
, "line_style"),
369 polyline
->line_style
);
371 if (polyline
->line_style
!= LINESTYLE_SOLID
&&
372 polyline
->dashlength
!= DEFAULT_LINESTYLE_DASHLEN
)
373 data_add_real(new_attribute(obj_node
, "dashlength"),
374 polyline
->dashlength
);
376 if (polyline
->start_arrow
.type
!= ARROW_NONE
) {
377 data_add_enum(new_attribute(obj_node
, "start_arrow"),
378 polyline
->start_arrow
.type
);
379 data_add_real(new_attribute(obj_node
, "start_arrow_length"),
380 polyline
->start_arrow
.length
);
381 data_add_real(new_attribute(obj_node
, "start_arrow_width"),
382 polyline
->start_arrow
.width
);
385 if (polyline
->end_arrow
.type
!= ARROW_NONE
) {
386 data_add_enum(new_attribute(obj_node
, "end_arrow"),
387 polyline
->end_arrow
.type
);
388 data_add_real(new_attribute(obj_node
, "end_arrow_length"),
389 polyline
->end_arrow
.length
);
390 data_add_real(new_attribute(obj_node
, "end_arrow_width"),
391 polyline
->end_arrow
.width
);
396 polyline_load(ObjectNode obj_node
, int version
, const char *filename
)
403 polyline
= g_malloc0(sizeof(Polyline
));
405 poly
= &polyline
->poly
;
408 obj
->type
= &polyline_type
;
409 obj
->ops
= &polyline_ops
;
411 polyconn_load(poly
, obj_node
);
413 polyline
->line_color
= color_black
;
414 attr
= object_find_attribute(obj_node
, "line_color");
416 data_color(attribute_first_data(attr
), &polyline
->line_color
);
418 polyline
->line_width
= 0.1;
419 attr
= object_find_attribute(obj_node
, "line_width");
421 polyline
->line_width
= data_real(attribute_first_data(attr
));
423 polyline
->line_style
= LINESTYLE_SOLID
;
424 attr
= object_find_attribute(obj_node
, "line_style");
426 polyline
->line_style
= data_enum(attribute_first_data(attr
));
428 polyline
->dashlength
= DEFAULT_LINESTYLE_DASHLEN
;
429 attr
= object_find_attribute(obj_node
, "dashlength");
431 polyline
->dashlength
= data_real(attribute_first_data(attr
));
433 polyline
->start_arrow
.type
= ARROW_NONE
;
434 polyline
->start_arrow
.length
= 0.8;
435 polyline
->start_arrow
.width
= 0.8;
436 attr
= object_find_attribute(obj_node
, "start_arrow");
438 polyline
->start_arrow
.type
= data_enum(attribute_first_data(attr
));
439 attr
= object_find_attribute(obj_node
, "start_arrow_length");
441 polyline
->start_arrow
.length
= data_real(attribute_first_data(attr
));
442 attr
= object_find_attribute(obj_node
, "start_arrow_width");
444 polyline
->start_arrow
.width
= data_real(attribute_first_data(attr
));
446 polyline
->end_arrow
.type
= ARROW_NONE
;
447 polyline
->end_arrow
.length
= 0.8;
448 polyline
->end_arrow
.width
= 0.8;
449 attr
= object_find_attribute(obj_node
, "end_arrow");
451 polyline
->end_arrow
.type
= data_enum(attribute_first_data(attr
));
452 attr
= object_find_attribute(obj_node
, "end_arrow_length");
454 polyline
->end_arrow
.length
= data_real(attribute_first_data(attr
));
455 attr
= object_find_attribute(obj_node
, "end_arrow_width");
457 polyline
->end_arrow
.width
= data_real(attribute_first_data(attr
));
459 polyline_update_data(polyline
);
461 return &polyline
->poly
.object
;
464 static ObjectChange
*
465 polyline_add_corner_callback (Object
*obj
, Point
*clicked
, gpointer data
)
467 Polyline
*poly
= (Polyline
*) obj
;
469 ObjectChange
*change
;
471 segment
= polyline_closest_segment(poly
, clicked
);
472 change
= polyconn_add_point(&poly
->poly
, segment
, clicked
);
473 polyline_update_data(poly
);
477 static ObjectChange
*
478 polyline_delete_corner_callback (Object
*obj
, Point
*clicked
, gpointer data
)
482 Polyline
*poly
= (Polyline
*) obj
;
483 ObjectChange
*change
;
485 handle
= polyline_closest_handle(poly
, clicked
);
487 for (i
= 0; i
< obj
->num_handles
; i
++) {
488 if (handle
== obj
->handles
[i
]) break;
491 change
= polyconn_remove_point(&poly
->poly
, handle_nr
);
492 polyline_update_data(poly
);
497 static DiaMenuItem polyline_menu_items
[] = {
498 { N_("Add Corner"), polyline_add_corner_callback
, NULL
, 1 },
499 { N_("Delete Corner"), polyline_delete_corner_callback
, NULL
, 1 },
502 static DiaMenu polyline_menu
= {
504 sizeof(polyline_menu_items
)/sizeof(DiaMenuItem
),
510 polyline_get_object_menu(Polyline
*polyline
, Point
*clickedpoint
)
512 /* Set entries sensitive/selected etc here */
513 polyline_menu_items
[0].active
= 1;
514 polyline_menu_items
[1].active
= polyline
->poly
.numpoints
> 2;
515 return &polyline_menu
;