1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
3 *
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <assert.h>
24 #include <math.h>
25
26 #include "intl.h"
27 #include "object.h"
28 #include "element.h"
29 #include "connectionpoint.h"
30 #include "diarenderer.h"
31 #include "attributes.h"
32 #include "widgets.h"
33 #include "message.h"
34 #include "properties.h"
35
36 #include "tool-icons.h"
37
38 #define DEFAULT_WIDTH 2.0
39 #define DEFAULT_HEIGHT 1.0
40 #define DEFAULT_BORDER 0.25
41
42 #define NUM_CONNECTIONS 9
43
44 typedef enum {
45 FREE_ASPECT,
46 FIXED_ASPECT,
47 SQUARE_ASPECT
48 } AspectType;
49
50 typedef struct _Box Box;
51
52 struct _Box {
53 Element element;
54
55 ConnectionPoint connections[NUM_CONNECTIONS];
56
57 real border_width;
58 Color border_color;
59 Color inner_color;
60 gboolean show_background;
61 LineStyle line_style;
62 real dashlength;
63 real corner_radius;
64 AspectType aspect;
65 };
66
67 static struct _BoxProperties {
68 gboolean show_background;
69 real corner_radius;
70 AspectType aspect;
71 } default_properties = { TRUE, 0.0 };
72
73 static real box_distance_from(Box *box, Point *point);
74 static void box_select(Box *box, Point *clicked_point,
75 DiaRenderer *interactive_renderer);
76 static ObjectChange* box_move_handle(Box *box, Handle *handle,
77 Point *to, ConnectionPoint *cp,
78 HandleMoveReason reason,
79 ModifierKeys modifiers);
80 static ObjectChange* box_move(Box *box, Point *to);
81 static void box_draw(Box *box, DiaRenderer *renderer);
82 static void box_update_data(Box *box);
83 static DiaObject *box_create(Point *startpoint,
84 void *user_data,
85 Handle **handle1,
86 Handle **handle2);
87 static void box_destroy(Box *box);
88 static DiaObject *box_copy(Box *box);
89
90 static PropDescription *box_describe_props(Box *box);
91 static void box_get_props(Box *box, GPtrArray *props);
92 static void box_set_props(Box *box, GPtrArray *props);
93
94 static void box_save(Box *box, ObjectNode obj_node, const char *filename);
95 static DiaObject *box_load(ObjectNode obj_node, int version, const char *filename);
96 static DiaMenu *box_get_object_menu(Box *box, Point *clickedpoint);
97
98 static ObjectTypeOps box_type_ops =
99 {
100 (CreateFunc) box_create,
101 (LoadFunc) box_load,
102 (SaveFunc) box_save,
103 (GetDefaultsFunc) NULL,
104 (ApplyDefaultsFunc) NULL
105 };
106
107 DiaObjectType box_type =
108 {
109 "Standard - Box", /* name */
110 0, /* version */
111 (char **) box_icon, /* pixmap */
112
113 &box_type_ops /* ops */
114 };
115
116 DiaObjectType *_box_type = (DiaObjectType *) &box_type;
117
118 static ObjectOps box_ops = {
119 (DestroyFunc) box_destroy,
120 (DrawFunc) box_draw,
121 (DistanceFunc) box_distance_from,
122 (SelectFunc) box_select,
123 (CopyFunc) box_copy,
124 (MoveFunc) box_move,
125 (MoveHandleFunc) box_move_handle,
126 (GetPropertiesFunc) object_create_props_dialog,
127 (ApplyPropertiesDialogFunc) object_apply_props_from_dialog,
128 (ObjectMenuFunc) box_get_object_menu,
129 (DescribePropsFunc) box_describe_props,
130 (GetPropsFunc) box_get_props,
131 (SetPropsFunc) box_set_props,
132 (TextEditFunc) 0,
133 (ApplyPropertiesListFunc) object_apply_props,
134 };
135
136 static PropNumData corner_radius_data = { 0.0, 10.0, 0.1 };
137
138 static PropEnumData prop_aspect_data[] = {
139 { N_("Free"), FREE_ASPECT },
140 { N_("Fixed"), FIXED_ASPECT },
141 { N_("Square"), SQUARE_ASPECT },
142 { NULL, 0 }
143 };
144 static PropDescription box_props[] = {
145 ELEMENT_COMMON_PROPERTIES,
146 PROP_STD_LINE_WIDTH,
147 PROP_STD_LINE_COLOUR,
148 PROP_STD_FILL_COLOUR,
149 PROP_STD_SHOW_BACKGROUND,
150 PROP_STD_LINE_STYLE,
151 { "corner_radius", PROP_TYPE_REAL, PROP_FLAG_VISIBLE,
152 N_("Corner radius"), NULL, &corner_radius_data },
153 { "aspect", PROP_TYPE_ENUM, PROP_FLAG_VISIBLE,
154 N_("Aspect ratio"), NULL, prop_aspect_data },
155 PROP_DESC_END
156 };
157
158 static PropDescription *
box_describe_props(Box * box)159 box_describe_props(Box *box)
160 {
161 if (box_props[0].quark == 0)
162 prop_desc_list_calculate_quarks(box_props);
163 return box_props;
164 }
165
166 static PropOffset box_offsets[] = {
167 ELEMENT_COMMON_PROPERTIES_OFFSETS,
168 { PROP_STDNAME_LINE_WIDTH, PROP_STDTYPE_LINE_WIDTH, offsetof(Box, border_width) },
169 { "line_colour", PROP_TYPE_COLOUR, offsetof(Box, border_color) },
170 { "fill_colour", PROP_TYPE_COLOUR, offsetof(Box, inner_color) },
171 { "show_background", PROP_TYPE_BOOL, offsetof(Box, show_background) },
172 { "aspect", PROP_TYPE_ENUM, offsetof(Box, aspect) },
173 { "line_style", PROP_TYPE_LINESTYLE,
174 offsetof(Box, line_style), offsetof(Box, dashlength) },
175 { "corner_radius", PROP_TYPE_REAL, offsetof(Box, corner_radius) },
176 { NULL, 0, 0 }
177 };
178
179 static void
box_get_props(Box * box,GPtrArray * props)180 box_get_props(Box *box, GPtrArray *props)
181 {
182 object_get_props_from_offsets(&box->element.object,
183 box_offsets, props);
184 }
185
186 static void
box_set_props(Box * box,GPtrArray * props)187 box_set_props(Box *box, GPtrArray *props)
188 {
189 object_set_props_from_offsets(&box->element.object,
190 box_offsets, props);
191 box_update_data(box);
192 }
193
194 static real
box_distance_from(Box * box,Point * point)195 box_distance_from(Box *box, Point *point)
196 {
197 Element *elem = &box->element;
198 Rectangle rect;
199
200 rect.left = elem->corner.x - box->border_width/2;
201 rect.right = elem->corner.x + elem->width + box->border_width/2;
202 rect.top = elem->corner.y - box->border_width/2;
203 rect.bottom = elem->corner.y + elem->height + box->border_width/2;
204 return distance_rectangle_point(&rect, point);
205 }
206
207 static void
box_select(Box * box,Point * clicked_point,DiaRenderer * interactive_renderer)208 box_select(Box *box, Point *clicked_point,
209 DiaRenderer *interactive_renderer)
210 {
211 real radius;
212
213 element_update_handles(&box->element);
214
215 if (box->corner_radius > 0) {
216 Element *elem = (Element *)box;
217 radius = box->corner_radius;
218 radius = MIN(radius, elem->width/2);
219 radius = MIN(radius, elem->height/2);
220 radius *= (1-M_SQRT1_2);
221
222 elem->resize_handles[0].pos.x += radius;
223 elem->resize_handles[0].pos.y += radius;
224 elem->resize_handles[2].pos.x -= radius;
225 elem->resize_handles[2].pos.y += radius;
226 elem->resize_handles[5].pos.x += radius;
227 elem->resize_handles[5].pos.y -= radius;
228 elem->resize_handles[7].pos.x -= radius;
229 elem->resize_handles[7].pos.y -= radius;
230 }
231 }
232
233 static ObjectChange*
box_move_handle(Box * box,Handle * handle,Point * to,ConnectionPoint * cp,HandleMoveReason reason,ModifierKeys modifiers)234 box_move_handle(Box *box, Handle *handle,
235 Point *to, ConnectionPoint *cp,
236 HandleMoveReason reason, ModifierKeys modifiers)
237 {
238 assert(box!=NULL);
239 assert(handle!=NULL);
240 assert(to!=NULL);
241
242 if (box->aspect != FREE_ASPECT){
243 double width, height;
244 double new_width, new_height;
245 double to_width, aspect_width;
246 Point corner = box->element.corner;
247 Point se_to;
248
249 width = box->element.width;
250 height = box->element.height;
251 switch (handle->id) {
252 case HANDLE_RESIZE_N:
253 case HANDLE_RESIZE_S:
254 new_height = fabs(to->y - corner.y);
255 new_width = new_height / height * width;
256 break;
257 case HANDLE_RESIZE_W:
258 case HANDLE_RESIZE_E:
259 new_width = fabs(to->x - corner.x);
260 new_height = new_width / width * height;
261 break;
262 case HANDLE_RESIZE_NW:
263 case HANDLE_RESIZE_NE:
264 case HANDLE_RESIZE_SW:
265 case HANDLE_RESIZE_SE:
266 to_width = fabs(to->x - corner.x);
267 aspect_width = fabs(to->y - corner.y) / height * width;
268 new_width = to_width > aspect_width ? to_width : aspect_width;
269 new_height = new_width / width * height;
270 break;
271 default:
272 new_width = width;
273 new_height = height;
274 break;
275 }
276
277 se_to.x = corner.x + new_width;
278 se_to.y = corner.y + new_height;
279
280 element_move_handle(&box->element, HANDLE_RESIZE_SE, &se_to, cp, reason, modifiers);
281 } else {
282 element_move_handle(&box->element, handle->id, to, cp, reason, modifiers);
283 }
284
285 box_update_data(box);
286
287 return NULL;
288 }
289
290 static ObjectChange*
box_move(Box * box,Point * to)291 box_move(Box *box, Point *to)
292 {
293 box->element.corner = *to;
294
295 box_update_data(box);
296
297 return NULL;
298 }
299
300 static void
box_draw(Box * box,DiaRenderer * renderer)301 box_draw(Box *box, DiaRenderer *renderer)
302 {
303 Point lr_corner;
304 Element *elem;
305 DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
306
307
308 assert(box != NULL);
309 assert(renderer != NULL);
310
311 elem = &box->element;
312
313 lr_corner.x = elem->corner.x + elem->width;
314 lr_corner.y = elem->corner.y + elem->height;
315
316 renderer_ops->set_linewidth(renderer, box->border_width);
317 renderer_ops->set_linestyle(renderer, box->line_style);
318 renderer_ops->set_dashlength(renderer, box->dashlength);
319 if (box->corner_radius > 0)
320 renderer_ops->set_linejoin(renderer, LINEJOIN_ROUND);
321 else
322 renderer_ops->set_linejoin(renderer, LINEJOIN_MITER);
323
324 if (box->show_background) {
325 renderer_ops->set_fillstyle(renderer, FILLSTYLE_SOLID);
326
327 /* Problem: How do we make the fill with rounded corners? */
328 if (box->corner_radius > 0) {
329 renderer_ops->fill_rounded_rect(renderer,
330 &elem->corner,
331 &lr_corner,
332 &box->inner_color,
333 box->corner_radius);
334 } else {
335 renderer_ops->fill_rect(renderer,
336 &elem->corner,
337 &lr_corner,
338 &box->inner_color);
339 }
340 }
341
342 if (box->corner_radius > 0) {
343 renderer_ops->draw_rounded_rect(renderer,
344 &elem->corner,
345 &lr_corner,
346 &box->border_color,
347 box->corner_radius);
348 } else {
349 renderer_ops->draw_rect(renderer,
350 &elem->corner,
351 &lr_corner,
352 &box->border_color);
353 }
354 }
355
356
357 static void
box_update_data(Box * box)358 box_update_data(Box *box)
359 {
360 Element *elem = &box->element;
361 ElementBBExtras *extra = &elem->extra_spacing;
362 DiaObject *obj = &elem->object;
363 real radius;
364
365 if (box->aspect == SQUARE_ASPECT){
366 float size = elem->height < elem->width ? elem->height : elem->width;
367 elem->height = elem->width = size;
368 }
369
370 radius = box->corner_radius;
371 radius = MIN(radius, elem->width/2);
372 radius = MIN(radius, elem->height/2);
373 radius *= (1-M_SQRT1_2);
374
375 /* Update connections: */
376 box->connections[0].pos.x = elem->corner.x + radius;
377 box->connections[0].pos.y = elem->corner.y + radius;
378 box->connections[1].pos.x = elem->corner.x + elem->width / 2.0;
379 box->connections[1].pos.y = elem->corner.y;
380 box->connections[2].pos.x = elem->corner.x + elem->width - radius;
381 box->connections[2].pos.y = elem->corner.y + radius;
382 box->connections[3].pos.x = elem->corner.x;
383 box->connections[3].pos.y = elem->corner.y + elem->height / 2.0;
384 box->connections[4].pos.x = elem->corner.x + elem->width;
385 box->connections[4].pos.y = elem->corner.y + elem->height / 2.0;
386 box->connections[5].pos.x = elem->corner.x + radius;
387 box->connections[5].pos.y = elem->corner.y + elem->height - radius;
388 box->connections[6].pos.x = elem->corner.x + elem->width / 2.0;
389 box->connections[6].pos.y = elem->corner.y + elem->height;
390 box->connections[7].pos.x = elem->corner.x + elem->width - radius;
391 box->connections[7].pos.y = elem->corner.y + elem->height - radius;
392 box->connections[8].pos.x = elem->corner.x + elem->width / 2.0;
393 box->connections[8].pos.y = elem->corner.y + elem->height / 2.0;
394
395 box->connections[0].directions = DIR_NORTH|DIR_WEST;
396 box->connections[1].directions = DIR_NORTH;
397 box->connections[2].directions = DIR_NORTH|DIR_EAST;
398 box->connections[3].directions = DIR_WEST;
399 box->connections[4].directions = DIR_EAST;
400 box->connections[5].directions = DIR_SOUTH|DIR_WEST;
401 box->connections[6].directions = DIR_SOUTH;
402 box->connections[7].directions = DIR_SOUTH|DIR_EAST;
403 box->connections[8].directions = DIR_ALL;
404
405 extra->border_trans = box->border_width / 2.0;
406 element_update_boundingbox(elem);
407
408 obj->position = elem->corner;
409
410 element_update_handles(elem);
411
412 if (radius > 0.0) {
413 /* Fix the handles, too */
414 elem->resize_handles[0].pos.x += radius;
415 elem->resize_handles[0].pos.y += radius;
416 elem->resize_handles[2].pos.x -= radius;
417 elem->resize_handles[2].pos.y += radius;
418 elem->resize_handles[5].pos.x += radius;
419 elem->resize_handles[5].pos.y -= radius;
420 elem->resize_handles[7].pos.x -= radius;
421 elem->resize_handles[7].pos.y -= radius;
422 }
423 }
424
425 static DiaObject *
box_create(Point * startpoint,void * user_data,Handle ** handle1,Handle ** handle2)426 box_create(Point *startpoint,
427 void *user_data,
428 Handle **handle1,
429 Handle **handle2)
430 {
431 Box *box;
432 Element *elem;
433 DiaObject *obj;
434 int i;
435
436 box = g_malloc0(sizeof(Box));
437 elem = &box->element;
438 obj = &elem->object;
439
440 obj->type = &box_type;
441
442 obj->ops = &box_ops;
443
444 elem->corner = *startpoint;
445 elem->width = DEFAULT_WIDTH;
446 elem->height = DEFAULT_HEIGHT;
447
448 box->border_width = attributes_get_default_linewidth();
449 box->border_color = attributes_get_foreground();
450 box->inner_color = attributes_get_background();
451 attributes_get_default_line_style(&box->line_style, &box->dashlength);
452 /* For non-default objects, this is overridden by the default */
453 box->show_background = default_properties.show_background;
454 box->corner_radius = default_properties.corner_radius;
455 box->aspect = default_properties.aspect;
456
457 element_init(elem, 8, NUM_CONNECTIONS);
458
459 for (i=0;i<NUM_CONNECTIONS;i++) {
460 obj->connections[i] = &box->connections[i];
461 box->connections[i].object = obj;
462 box->connections[i].connected = NULL;
463 }
464 box->connections[8].flags = CP_FLAGS_MAIN;
465
466 box_update_data(box);
467
468 *handle1 = NULL;
469 *handle2 = obj->handles[7];
470 return &box->element.object;
471 }
472
473 static void
box_destroy(Box * box)474 box_destroy(Box *box)
475 {
476 element_destroy(&box->element);
477 }
478
479 static DiaObject *
box_copy(Box * box)480 box_copy(Box *box)
481 {
482 int i;
483 Box *newbox;
484 Element *elem, *newelem;
485 DiaObject *newobj;
486
487 elem = &box->element;
488
489 newbox = g_malloc0(sizeof(Box));
490 newelem = &newbox->element;
491 newobj = &newelem->object;
492
493 element_copy(elem, newelem);
494
495 newbox->border_width = box->border_width;
496 newbox->border_color = box->border_color;
497 newbox->inner_color = box->inner_color;
498 newbox->show_background = box->show_background;
499 newbox->line_style = box->line_style;
500 newbox->dashlength = box->dashlength;
501 newbox->corner_radius = box->corner_radius;
502 newbox->aspect = box->aspect;
503
504 for (i=0;i<NUM_CONNECTIONS;i++) {
505 newobj->connections[i] = &newbox->connections[i];
506 newbox->connections[i].object = newobj;
507 newbox->connections[i].connected = NULL;
508 newbox->connections[i].pos = box->connections[i].pos;
509 newbox->connections[i].last_pos = box->connections[i].last_pos;
510 newbox->connections[i].flags = box->connections[i].flags;
511 }
512
513 return &newbox->element.object;
514 }
515
516 static void
box_save(Box * box,ObjectNode obj_node,const char * filename)517 box_save(Box *box, ObjectNode obj_node, const char *filename)
518 {
519 element_save(&box->element, obj_node);
520
521 if (box->border_width != 0.1)
522 data_add_real(new_attribute(obj_node, "border_width"),
523 box->border_width);
524
525 if (!color_equals(&box->border_color, &color_black))
526 data_add_color(new_attribute(obj_node, "border_color"),
527 &box->border_color);
528
529 if (!color_equals(&box->inner_color, &color_white))
530 data_add_color(new_attribute(obj_node, "inner_color"),
531 &box->inner_color);
532
533 data_add_boolean(new_attribute(obj_node, "show_background"), box->show_background);
534
535 if (box->line_style != LINESTYLE_SOLID)
536 data_add_enum(new_attribute(obj_node, "line_style"),
537 box->line_style);
538
539 if (box->line_style != LINESTYLE_SOLID &&
540 box->dashlength != DEFAULT_LINESTYLE_DASHLEN)
541 data_add_real(new_attribute(obj_node, "dashlength"),
542 box->dashlength);
543
544 if (box->corner_radius > 0.0)
545 data_add_real(new_attribute(obj_node, "corner_radius"),
546 box->corner_radius);
547
548 if (box->aspect != FREE_ASPECT)
549 data_add_enum(new_attribute(obj_node, "aspect"),
550 box->aspect);
551 }
552
553 static DiaObject *
box_load(ObjectNode obj_node,int version,const char * filename)554 box_load(ObjectNode obj_node, int version, const char *filename)
555 {
556 Box *box;
557 Element *elem;
558 DiaObject *obj;
559 int i;
560 AttributeNode attr;
561
562 box = g_malloc0(sizeof(Box));
563 elem = &box->element;
564 obj = &elem->object;
565
566 obj->type = &box_type;
567 obj->ops = &box_ops;
568
569 element_load(elem, obj_node);
570
571 box->border_width = 0.1;
572 attr = object_find_attribute(obj_node, "border_width");
573 if (attr != NULL)
574 box->border_width = data_real( attribute_first_data(attr) );
575
576 box->border_color = color_black;
577 attr = object_find_attribute(obj_node, "border_color");
578 if (attr != NULL)
579 data_color(attribute_first_data(attr), &box->border_color);
580
581 box->inner_color = color_white;
582 attr = object_find_attribute(obj_node, "inner_color");
583 if (attr != NULL)
584 data_color(attribute_first_data(attr), &box->inner_color);
585
586 box->show_background = TRUE;
587 attr = object_find_attribute(obj_node, "show_background");
588 if (attr != NULL)
589 box->show_background = data_boolean( attribute_first_data(attr) );
590
591 box->line_style = LINESTYLE_SOLID;
592 attr = object_find_attribute(obj_node, "line_style");
593 if (attr != NULL)
594 box->line_style = data_enum( attribute_first_data(attr) );
595
596 box->dashlength = DEFAULT_LINESTYLE_DASHLEN;
597 attr = object_find_attribute(obj_node, "dashlength");
598 if (attr != NULL)
599 box->dashlength = data_real(attribute_first_data(attr));
600
601 box->corner_radius = 0.0;
602 attr = object_find_attribute(obj_node, "corner_radius");
603 if (attr != NULL)
604 box->corner_radius = data_real( attribute_first_data(attr) );
605
606 box->aspect = FREE_ASPECT;
607 attr = object_find_attribute(obj_node, "aspect");
608 if (attr != NULL)
609 box->aspect = data_enum(attribute_first_data(attr));
610
611 element_init(elem, 8, NUM_CONNECTIONS);
612
613 for (i=0;i<NUM_CONNECTIONS;i++) {
614 obj->connections[i] = &box->connections[i];
615 box->connections[i].object = obj;
616 box->connections[i].connected = NULL;
617 }
618 box->connections[8].flags = CP_FLAGS_MAIN;
619
620 box_update_data(box);
621
622 return &box->element.object;
623 }
624
625
626 struct AspectChange {
627 ObjectChange obj_change;
628 AspectType old_type, new_type;
629 /* The points before this got applied. Afterwards, all points can be
630 * calculated.
631 */
632 Point topleft;
633 real width, height;
634 };
635
636 static void
aspect_change_free(struct AspectChange * change)637 aspect_change_free(struct AspectChange *change)
638 {
639 }
640
641 static void
aspect_change_apply(struct AspectChange * change,DiaObject * obj)642 aspect_change_apply(struct AspectChange *change, DiaObject *obj)
643 {
644 Box *box = (Box*)obj;
645
646 box->aspect = change->new_type;
647 box_update_data(box);
648 }
649
650 static void
aspect_change_revert(struct AspectChange * change,DiaObject * obj)651 aspect_change_revert(struct AspectChange *change, DiaObject *obj)
652 {
653 Box *box = (Box*)obj;
654
655 box->aspect = change->old_type;
656 box->element.corner = change->topleft;
657 box->element.width = change->width;
658 box->element.height = change->height;
659 box_update_data(box);
660 }
661
662 static ObjectChange *
aspect_create_change(Box * box,AspectType aspect)663 aspect_create_change(Box *box, AspectType aspect)
664 {
665 struct AspectChange *change;
666
667 change = g_new0(struct AspectChange, 1);
668
669 change->obj_change.apply = (ObjectChangeApplyFunc) aspect_change_apply;
670 change->obj_change.revert = (ObjectChangeRevertFunc) aspect_change_revert;
671 change->obj_change.free = (ObjectChangeFreeFunc) aspect_change_free;
672
673 change->old_type = box->aspect;
674 change->new_type = aspect;
675 change->topleft = box->element.corner;
676 change->width = box->element.width;
677 change->height = box->element.height;
678
679 return (ObjectChange *)change;
680 }
681
682
683 static ObjectChange *
box_set_aspect_callback(DiaObject * obj,Point * clicked,gpointer data)684 box_set_aspect_callback (DiaObject* obj, Point* clicked, gpointer data)
685 {
686 ObjectChange *change;
687
688 change = aspect_create_change((Box*)obj, (AspectType)data);
689 change->apply(change, obj);
690
691 return change;
692 }
693
694 static DiaMenuItem box_menu_items[] = {
695 { N_("Free aspect"), box_set_aspect_callback, (void*)FREE_ASPECT,
696 DIAMENU_ACTIVE|DIAMENU_TOGGLE },
697 { N_("Fixed aspect"), box_set_aspect_callback, (void*)FIXED_ASPECT,
698 DIAMENU_ACTIVE|DIAMENU_TOGGLE },
699 { N_("Square"), box_set_aspect_callback, (void*)SQUARE_ASPECT,
700 DIAMENU_ACTIVE|DIAMENU_TOGGLE},
701 };
702
703 static DiaMenu box_menu = {
704 "Box",
705 sizeof(box_menu_items)/sizeof(DiaMenuItem),
706 box_menu_items,
707 NULL
708 };
709
710 static DiaMenu *
box_get_object_menu(Box * box,Point * clickedpoint)711 box_get_object_menu(Box *box, Point *clickedpoint)
712 {
713 /* Set entries sensitive/selected etc here */
714 box_menu_items[0].active = DIAMENU_ACTIVE|DIAMENU_TOGGLE;
715 box_menu_items[1].active = DIAMENU_ACTIVE|DIAMENU_TOGGLE;
716 box_menu_items[2].active = DIAMENU_ACTIVE|DIAMENU_TOGGLE;
717
718 box_menu_items[box->aspect].active =
719 DIAMENU_ACTIVE|DIAMENU_TOGGLE|DIAMENU_TOGGLE_ON;
720
721 return &box_menu;
722 }
723