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 /** \file diagramdata.c This file defines the DiagramData object, which holds (mostly) saveable
20 * data global to a diagram.
28 #include "diagramdata.h"
29 #include "diarenderer.h"
31 #include "persistence.h"
33 #include "dynamic_obj.h"
34 #include "diamarshal.h"
37 static const Rectangle invalid_extents
= { -1.0,-1.0,-1.0,-1.0 };
38 static void set_parent_layer(gpointer layer
, gpointer object
);
40 static void diagram_data_class_init (DiagramDataClass
*klass
);
41 static void diagram_data_init (DiagramData
*object
);
49 static guint diagram_data_signals
[LAST_SIGNAL
] = { 0, };
51 static gpointer parent_class
= NULL
;
53 /** Get the type object for the DiagramData class.
56 diagram_data_get_type(void)
58 static GType object_type
= 0;
62 static const GTypeInfo object_info
=
64 sizeof (DiagramDataClass
),
66 (GBaseFinalizeFunc
) NULL
,
67 (GClassInitFunc
) diagram_data_class_init
,
68 NULL
, /* class_finalize */
69 NULL
, /* class_data */
72 (GInstanceInitFunc
)diagram_data_init
/* init */
75 object_type
= g_type_register_static (G_TYPE_OBJECT
,
83 /* signal default handlers */
85 _diagram_data_object_add (DiagramData
* dia
,Layer
* layer
,DiaObject
* obj
)
90 _diagram_data_object_remove (DiagramData
* dia
,Layer
* layer
,DiaObject
* obj
)
94 /** Initialize a new diagram data object.
95 * @param data A diagram data object to initialize.
98 diagram_data_init(DiagramData
*data
)
100 Color
* color
= persistence_register_color ("new_diagram_bgcolour", &color_white
);
101 gboolean compress
= persistence_register_boolean ("compress_save", TRUE
);
104 data
->extents
.left
= 0.0;
105 data
->extents
.right
= 10.0;
106 data
->extents
.top
= 0.0;
107 data
->extents
.bottom
= 10.0;
109 data
->bg_color
= *color
;
111 get_paper_info (&data
->paper
, -1, NULL
);
113 first_layer
= new_layer(g_strdup(_("Background")),data
);
115 data
->layers
= g_ptr_array_new ();
116 g_ptr_array_add (data
->layers
, first_layer
);
117 data
->active_layer
= first_layer
;
119 data
->selected_count_private
= 0;
120 data
->selected
= NULL
;
122 data
->is_compressed
= compress
; /* Overridden by doc */
126 /** Deallocate memory owned by a DiagramData object.
127 * @param object A DiagramData object to finalize.
130 diagram_data_finalize(GObject
*object
)
132 DiagramData
*data
= DIA_DIAGRAM_DATA(object
);
136 g_free(data
->paper
.name
);
138 for (i
=0;i
<data
->layers
->len
;i
++) {
139 layer_destroy(g_ptr_array_index(data
->layers
, i
));
141 g_ptr_array_free(data
->layers
, TRUE
);
142 data
->active_layer
= NULL
;
144 g_list_free(data
->selected
);
145 data
->selected
= NULL
; /* for safety */
146 data
->selected_count_private
= 0;
149 /** Initialize the DiagramData class data.
150 * @param klass The class object to initialize functions for.
153 diagram_data_class_init(DiagramDataClass
*klass
)
155 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
157 parent_class
= g_type_class_peek_parent (klass
);
159 diagram_data_signals
[OBJECT_ADD
] =
160 g_signal_new ("object_add",
161 G_TYPE_FROM_CLASS (klass
),
163 G_STRUCT_OFFSET (DiagramDataClass
, object_add
),
165 dia_marshal_VOID__POINTER_POINTER
,
171 diagram_data_signals
[OBJECT_REMOVE
] =
172 g_signal_new ("object_remove",
173 G_TYPE_FROM_CLASS (klass
),
175 G_STRUCT_OFFSET (DiagramDataClass
, object_remove
),
177 dia_marshal_VOID__POINTER_POINTER
,
183 object_class
->finalize
= diagram_data_finalize
;
184 klass
->object_add
= _diagram_data_object_add
;
185 klass
->object_remove
= _diagram_data_object_remove
;
188 /** Create a new layer in this diagram.
189 * @param name Name of the new layer.
190 * @param parent The DiagramData that the layer will belong to,.
191 * @return A new Layer object.
192 * @bug Must determine if a NULL name is ok.
193 * @bug This belongs in a layers.c file.
194 * @bug Even though this sets parent diagram, it doesn't call the
195 * update_extents functions that add_layer does.
198 new_layer(gchar
*name
, DiagramData
*parent
)
202 layer
= g_new(Layer
, 1);
206 layer
->parent_diagram
= parent
;
207 layer
->visible
= TRUE
;
208 layer
->connectable
= TRUE
;
210 layer
->objects
= NULL
;
212 layer
->extents
.left
= 0.0;
213 layer
->extents
.right
= 10.0;
214 layer
->extents
.top
= 0.0;
215 layer
->extents
.bottom
= 10.0;
220 /** Destroy a layer object.
221 * @param layer The layer object to deallocate entirely.
222 * @bug This belongs in a layers.c file.
225 layer_destroy(Layer
*layer
)
228 destroy_object_list(layer
->objects
);
232 /** Raise a layer up one in a diagram.
233 * @param data The diagram that the layer belongs to.
234 * @param layer The layer to raise.
235 * @bug The diagram doesn't really need to be passed, as the layer knows it.
238 data_raise_layer(DiagramData
*data
, Layer
*layer
)
244 for (i
=0;i
<data
->layers
->len
;i
++) {
245 if (g_ptr_array_index(data
->layers
, i
)==layer
)
249 g_assert(layer_nr
>=0);
251 if (layer_nr
< data
->layers
->len
-1) {
252 tmp
= g_ptr_array_index(data
->layers
, layer_nr
+1);
253 g_ptr_array_index(data
->layers
, layer_nr
+1) =
254 g_ptr_array_index(data
->layers
, layer_nr
);
255 g_ptr_array_index(data
->layers
, layer_nr
) = tmp
;
259 /** Lower a layer by one in a diagram.
260 * @param data The diagram that the layer belongs to.
261 * @param layer The layer to lower.
262 * @bug The diagram doesn't really need to be passed, as the layer knows it.
265 data_lower_layer(DiagramData
*data
, Layer
*layer
)
271 for (i
=0;i
<data
->layers
->len
;i
++) {
272 if (g_ptr_array_index(data
->layers
, i
)==layer
)
276 g_assert(layer_nr
>=0);
279 tmp
= g_ptr_array_index(data
->layers
, layer_nr
-1);
280 g_ptr_array_index(data
->layers
, layer_nr
-1) =
281 g_ptr_array_index(data
->layers
, layer_nr
);
282 g_ptr_array_index(data
->layers
, layer_nr
) = tmp
;
286 /** Add a layer object to a diagram.
287 * @param data The diagram to add the layer to.
288 * @param layer The layer to add.
289 * @bug Should just call data_add_layer_at().
292 data_add_layer(DiagramData
*data
, Layer
*layer
)
294 g_ptr_array_add(data
->layers
, layer
);
295 layer
->parent_diagram
= data
;
296 layer_update_extents(layer
);
297 data_update_extents(data
);
301 data_add_layer_at(DiagramData
*data
, Layer
*layer
, int pos
)
306 g_ptr_array_add(data
->layers
, layer
);
307 len
= data
->layers
->len
;
309 if ( (pos
>=0) && (pos
< len
)) {
310 for (i
=len
-1;i
>pos
;i
--) {
311 g_ptr_array_index(data
->layers
, i
) = g_ptr_array_index(data
->layers
, i
-1);
313 g_ptr_array_index(data
->layers
, pos
) = layer
;
316 layer
->parent_diagram
= data
;
317 layer_update_extents(layer
);
318 data_update_extents(data
);
321 /** Set which layer is the active layer in a diagram.
322 * @param data The diagram in which to set the active layer.
323 * @param layer The layer that should be active.
324 * @bug The diagram doesn't really need to be passed, as the layer knows it.
327 data_set_active_layer(DiagramData
*data
, Layer
*layer
)
329 data
->active_layer
= layer
;
332 /** Delete a layer from a diagram.
333 * @param data The diagram to delete the layer from.
334 * @param layer The layer to delete.
335 * @bug The diagram doesn't really need to be passed, as the layer knows it.
338 data_delete_layer(DiagramData
*data
, Layer
*layer
)
340 if (data
->layers
->len
<=1)
343 if (data
->active_layer
== layer
) {
344 data_remove_all_selected(data
);
346 layer
->parent_diagram
= NULL
;
347 g_ptr_array_remove(data
->layers
, layer
);
349 if (data
->active_layer
== layer
) {
350 data
->active_layer
= g_ptr_array_index(data
->layers
, 0);
354 /** Select an object in a diagram. Note that this does not unselect other
355 * objects currently selected in the diagram.
356 * @param data The diagram to select in.
357 * @param obj The object to select.
358 * @bug Does not need to be passed the diagram, as it can be found from the
362 data_select(DiagramData
*data
, DiaObject
*obj
)
364 if (g_list_find (data
->selected
, obj
))
365 return; /* should this be an error?`*/
366 data
->selected
= g_list_prepend(data
->selected
, obj
);
367 data
->selected_count_private
++;
370 /** Deselect an object in a diagram. Note that other objects may still be
371 * selected after this function is done.
372 * @param data The diagram to deselect in.
373 * @param obj The object to deselect.
374 * @bug Does not need to be passed the diagram, as it can be found from the
378 data_unselect(DiagramData
*data
, DiaObject
*obj
)
380 if (!g_list_find (data
->selected
, obj
))
381 return; /* should this be an error?`*/
382 data
->selected
= g_list_remove(data
->selected
, obj
);
383 data
->selected_count_private
--;
386 /** Clears the list of selected objects.
387 * Does *not* remove these objects from the object list, despite its name.
388 * @param data The diagram to unselect all objects in.
391 data_remove_all_selected(DiagramData
*data
)
393 g_list_free(data
->selected
); /* Remove previous selection */
394 data
->selected
= NULL
;
395 data
->selected_count_private
= 0;
398 /** Return TRUE if the diagram has visible layers.
399 * @param data The diagram to check.
400 * @return TRUE if at least one layer in the diagram is visible.
403 data_has_visible_layers(DiagramData
*data
)
406 for (i
= 0; i
< data
->layers
->len
; i
++) {
407 Layer
*layer
= g_ptr_array_index(data
->layers
, i
);
408 if (layer
->visible
) return TRUE
;
413 /** Set the diagram extents field to the union of the extents of the layers.
414 * @param data The diagram to get the extents for.
417 data_get_layers_extents_union(DiagramData
*data
)
420 gboolean first
= TRUE
;
421 Rectangle new_extents
;
423 for ( i
= 0 ; i
<data
->layers
->len
; i
++) {
424 Layer
*layer
= g_ptr_array_index(data
->layers
, i
);
425 if (!layer
->visible
) continue;
427 layer_update_extents(layer
);
430 new_extents
= layer
->extents
;
431 first
= rectangle_equals(&new_extents
,&invalid_extents
);
433 if (!rectangle_equals(&layer
->extents
,&invalid_extents
)) {
434 rectangle_union(&new_extents
, &layer
->extents
);
439 data
->extents
= new_extents
;
442 /** Change diagram scaling so that the extents are exactly visible.
443 * @param data The diagram to adjust.
444 * @bug Consider making it a teeny bit larger, or check that *all* objects
445 * calculate their extents correctly.
448 data_adapt_scaling_to_extents(DiagramData
*data
)
450 gdouble pwidth
= data
->paper
.width
* data
->paper
.scaling
;
451 gdouble pheight
= data
->paper
.height
* data
->paper
.scaling
;
453 gdouble xscale
= data
->paper
.fitwidth
* pwidth
/
454 (data
->extents
.right
- data
->extents
.left
);
455 gdouble yscale
= data
->paper
.fitheight
* pheight
/
456 (data
->extents
.bottom
- data
->extents
.top
);
458 data
->paper
.scaling
= (float)MIN(xscale
, yscale
);
459 data
->paper
.width
= (float)(pwidth
/ data
->paper
.scaling
);
460 data
->paper
.height
= (float)(pheight
/ data
->paper
.scaling
);
463 /** Adjust the extents field of a diagram.
464 * @param data The diagram to adjust.
465 * @return TRUE if the extents changed.
468 data_compute_extents(DiagramData
*data
)
470 Rectangle old_extents
= data
->extents
;
472 if (!data_has_visible_layers(data
)) {
473 if (data
->layers
->len
> 0) {
474 Layer
*layer
= g_ptr_array_index(data
->layers
, 0);
475 layer_update_extents(layer
);
477 data
->extents
= layer
->extents
;
479 data
->extents
= invalid_extents
;
482 data_get_layers_extents_union(data
);
485 if (rectangle_equals(&data
->extents
,&invalid_extents
)) {
486 data
->extents
.left
= 0.0;
487 data
->extents
.right
= 10.0;
488 data
->extents
.top
= 0.0;
489 data
->extents
.bottom
= 10.0;
491 return (!rectangle_equals(&data
->extents
,&old_extents
));
494 /** Update the extents of a diagram and adjust scaling if needed.
495 * @param data Diagram to update.
496 * @return TRUE if the diagram extents changed.
499 data_update_extents(DiagramData
*data
)
504 changed
= data_compute_extents(data
);
505 if (changed
&& data
->paper
.fitto
) data_adapt_scaling_to_extents(data
);
510 /** Get a list of selected objects in layer ordering.
511 * @param data The diagram to get objects from.
512 * @return A list of all currently selected objects. These all reside in
513 * the currently active layer. This list should be freed after use.
514 * @bug Does selection update correctly when the layer changes?
517 data_get_sorted_selected(DiagramData
*data
)
524 g_assert (g_list_length (data
->selected
) == data
->selected_count_private
);
525 if (data
->selected_count_private
== 0)
529 list
= g_list_last(data
->active_layer
->objects
);
530 while (list
!= NULL
) {
531 found
= g_list_find(data
->selected
, list
->data
);
533 obj
= (DiaObject
*)found
->data
;
534 sorted_list
= g_list_prepend(sorted_list
, obj
);
536 list
= g_list_previous(list
);
542 /** Remove the currently selected objects from the list of objects.
543 * The selected objects are returned in a newly created GList.
544 * @param data The diagram to get and remove the selected objects from.
545 * @return A list of all selected objects in the current diagram. This list
546 * should be freed after use. Unlike data_get_sorted_selected, the
547 * objects in the list are not in the diagram anymore.
550 data_get_sorted_selected_remove(DiagramData
*data
)
557 g_assert (g_list_length (data
->selected
) == data
->selected_count_private
);
558 if (data
->selected_count_private
== 0)
562 list
= g_list_last(data
->active_layer
->objects
);
563 while (list
!= NULL
) {
564 found
= g_list_find(data
->selected
, list
->data
);
566 obj
= (DiaObject
*)found
->data
;
567 sorted_list
= g_list_prepend(sorted_list
, obj
);
570 list
= g_list_previous(list
);
571 data
->active_layer
->objects
=
572 g_list_remove_link(data
->active_layer
->objects
, tmp
);
574 list
= g_list_previous(list
);
582 /** Emits a GObject signal on DiagramData
583 * @param data The DiagramData that emits the signal.
584 * @param layer The Layer that the fired signal carries.
585 * @param obj The DiaObject that the fired signal carries.
586 * @param signal_name The name of the signal.
589 data_emit(DiagramData
*data
, Layer
*layer
, DiaObject
* obj
,
590 const char *signal_name
)
592 /* check what signal it is */
593 if (strcmp("object_add",signal_name
) == 0)
594 g_signal_emit(data
, diagram_data_signals
[OBJECT_ADD
], 0, layer
, obj
);
596 if (strcmp("object_remove",signal_name
) == 0)
597 g_signal_emit(data
, diagram_data_signals
[OBJECT_REMOVE
], 0, layer
, obj
);
602 /** Render a diagram.
603 * @param data The diagram to render.
604 * @param renderer The renderer to render on.
605 * @param update The area that needs updating.
606 * @param obj_renderer If non-NULL, an alternative renderer of objects.
607 * @param gdata User data passed on to inner calls.
608 * @bug Describe obj_renderer better.
611 data_render(DiagramData
*data
, DiaRenderer
*renderer
, Rectangle
*update
,
612 ObjectRenderer obj_renderer
,
619 if (!renderer
->is_interactive
) (DIA_RENDERER_GET_CLASS(renderer
)->begin_render
)(renderer
);
621 for (i
=0; i
<data
->layers
->len
; i
++) {
622 layer
= (Layer
*) g_ptr_array_index(data
->layers
, i
);
623 active_layer
= (layer
== data
->active_layer
);
625 layer_render(layer
, renderer
, update
, obj_renderer
, gdata
, active_layer
);
628 if (!renderer
->is_interactive
) (DIA_RENDERER_GET_CLASS(renderer
)->end_render
)(renderer
);
631 /** The default object renderer.
632 * @param obj An object to render.
633 * @param renderer The renderer to render on.
634 * @param active_layer The layer containing the object.
635 * @param data The diagram containing the layer.
636 * @bug The active_layer and data variables can be inferred from the object.
639 normal_render(DiaObject
*obj
, DiaRenderer
*renderer
,
643 DIA_RENDERER_GET_CLASS(renderer
)->draw_object(renderer
, obj
);
647 int render_bounding_boxes
= FALSE
;
649 /** Render all components of a single layer. This function also handles
650 * rendering of bounding boxes for debugging purposes.
651 * @param layer The layer to render.
652 * @param renderer The renderer to draw things with.
653 * @param update The rectangle that requires update. Only objects that
654 * intersect with this rectangle will actually be get rendered.
655 * @param obj_renderer A function that will render an object.
656 * @param data The diagram that the layer belongs to.
657 * @param active_layer Which number layer in the diagram is currently active.
658 * @bug data and active_layer can be inferred from layer, though possibly
662 layer_render(Layer
*layer
, DiaRenderer
*renderer
, Rectangle
*update
,
663 ObjectRenderer obj_renderer
,
670 if (obj_renderer
== NULL
)
671 obj_renderer
= normal_render
;
673 /* Draw all objects: */
674 list
= layer
->objects
;
676 obj
= (DiaObject
*) list
->data
;
678 if (update
==NULL
|| rectangle_intersects(update
, &obj
->bounding_box
)) {
679 if ((render_bounding_boxes
) && (renderer
->is_interactive
)) {
682 p1
.x
= obj
->bounding_box
.left
;
683 p1
.y
= obj
->bounding_box
.top
;
684 p2
.x
= obj
->bounding_box
.right
;
685 p2
.y
= obj
->bounding_box
.bottom
;
690 DIA_RENDERER_GET_CLASS(renderer
)->set_linewidth(renderer
,0.01);
691 DIA_RENDERER_GET_CLASS(renderer
)->draw_rect(renderer
, &p1
, &p2
, &col
);
693 (*obj_renderer
)(obj
, renderer
, active_layer
, data
);
696 list
= g_list_next(list
);
700 /** Set the parent layer of an object.
701 * @param element A DiaObject that should be part of a layer.
702 * @param user_data The layer it should be part of.
705 set_parent_layer(gpointer element
, gpointer user_data
)
707 ((DiaObject
*)element
)->parent_layer
= (Layer
*)user_data
;
708 /* FIXME: even group members need a parent_layer and what about parent objects ???
709 * Now I know again why I always try to avoid back-pointers )-; --hb.
710 * If the group objects didn't actually leave the diagram, this wouldn't
711 * be a problem. --LC */
714 /** Get the index of an object in a layer.
715 * @param layer The layer the object is (should be) in.
716 * @param obj The object to look for.
717 * @return The index of the object in the layers list of objects. This is also
718 * the vertical position of the object.
719 * @bug This should be in a separate layer.c file.
720 * @bug The layer could be inferred from the object, in which case the
721 * layer arg is not needed, and we would be sure we always looked in the
725 layer_object_index(Layer
*layer
, DiaObject
*obj
)
727 return (int)g_list_index(layer
->objects
, (gpointer
) obj
);
730 /** Add an object to the top of a layer.
731 * @param layer The layer to add the object to.
732 * @param obj The object to add. This must not already be part of another
734 * @bug This should be in a separate layer.c file.
735 * @bug This should just call layer_add_object_at().
738 layer_add_object(Layer
*layer
, DiaObject
*obj
)
740 layer
->objects
= g_list_append(layer
->objects
, (gpointer
) obj
);
741 set_parent_layer(obj
, layer
);
743 /* send a signal that we have added a object to the diagram */
744 g_signal_emit (layer_get_parent_diagram(layer
), diagram_data_signals
[OBJECT_ADD
], 0,layer
,obj
);
747 /** Add an object to a layer at a specific position.
748 * @param layer The layer to add the object to.
749 * @param obj The object to add. This must not be part of another layer.
750 * @param pos The top-to-bottom position this object should be inserted at.
751 * @bug This should be in a separate layer.c file.
754 layer_add_object_at(Layer
*layer
, DiaObject
*obj
, int pos
)
756 layer
->objects
= g_list_insert(layer
->objects
, (gpointer
) obj
, pos
);
757 set_parent_layer(obj
, layer
);
759 /* send a signal that we have added a object to the diagram */
760 g_signal_emit (layer_get_parent_diagram(layer
), diagram_data_signals
[OBJECT_ADD
], 0,layer
,obj
);
763 /** Add a list of objects to the end of a layer.
764 * @param layer The layer to add objects to.
765 * @param obj_list The list of objects to add. These must not already
766 * be part of another layer.
767 * @bug Determine if the list is kept by g_list_concat.
770 layer_add_objects(Layer
*layer
, GList
*obj_list
)
772 GList
*list
= obj_list
;
774 layer
->objects
= g_list_concat(layer
->objects
, obj_list
);
775 g_list_foreach(obj_list
, set_parent_layer
, layer
);
779 /* send a signal that we have added a object to the diagram */
780 g_signal_emit (layer_get_parent_diagram(layer
), diagram_data_signals
[OBJECT_ADD
], 0,layer
,list
->data
);
782 list
= g_list_next(list
);
786 /** Add a list of objects to the top of a layer.
787 * @param layer The layer to add objects to.
788 * @param obj_list The list of objects to add. These must not already
789 * be part of another layer.
790 * @bug Determine if the list is kept by g_list_concat.
793 layer_add_objects_first(Layer
*layer
, GList
*obj_list
)
795 GList
*list
= obj_list
;
797 layer
->objects
= g_list_concat(obj_list
, layer
->objects
);
798 g_list_foreach(obj_list
, set_parent_layer
, layer
);
800 /* Send one signal per object added */
803 /* send a signal that we have added a object to the diagram */
804 g_signal_emit (layer_get_parent_diagram(layer
), diagram_data_signals
[OBJECT_ADD
], 0,layer
,list
->data
);
806 list
= g_list_next(list
);
811 /** Remove an object from a layer.
812 * @param layer The layer to remove the object from.
813 * @param obj The object to remove.
814 * @bug Why don't the layer_add functions deal with dynobj?
817 layer_remove_object(Layer
*layer
, DiaObject
*obj
)
819 layer
->objects
= g_list_remove(layer
->objects
, obj
);
820 dynobj_list_remove_object(obj
);
821 set_parent_layer(obj
, NULL
);
823 /* send a signal that we have removed a object from the diagram */
824 g_signal_emit (layer_get_parent_diagram(layer
), diagram_data_signals
[OBJECT_REMOVE
], 0,layer
,obj
);
827 /** Remove a list of objects from a layer.
828 * @param layer The layer to remove the objects from.
829 * @param obj The objects to remove.
830 * @bug This should call layer_remove_object repeatedly.
833 layer_remove_objects(Layer
*layer
, GList
*obj_list
)
836 while (obj_list
!= NULL
) {
837 obj
= (DiaObject
*) obj_list
->data
;
839 layer
->objects
= g_list_remove(layer
->objects
, obj
);
841 obj_list
= g_list_next(obj_list
);
842 dynobj_list_remove_object(obj
);
843 set_parent_layer(obj
, NULL
);
844 /* send a signal that we have removed a object from the diagram */
845 g_signal_emit (layer_get_parent_diagram(layer
), diagram_data_signals
[OBJECT_REMOVE
], 0,layer
,obj
);
849 /** Find the objects that intersect a given rectangle.
850 * @param layer The layer to search in.
851 * @param rect The rectangle to intersect with.
852 * @return List of objects whose bounding box intersect the rectangle. The
853 * list should be freed by the caller.
856 layer_find_objects_intersecting_rectangle(Layer
*layer
, Rectangle
*rect
)
859 GList
*selected_list
;
862 selected_list
= NULL
;
863 list
= layer
->objects
;
864 while (list
!= NULL
) {
865 obj
= (DiaObject
*)list
->data
;
867 if (rectangle_intersects(rect
, &obj
->bounding_box
)) {
868 if (dia_object_is_selectable(obj
)) {
869 selected_list
= g_list_prepend(selected_list
, obj
);
871 /* Objects in closed groups do not get selected, but their parents do.
872 * Since the parents bbox is outside the objects, they will be found
873 * anyway and the inner object can just be skipped. */
876 list
= g_list_next(list
);
879 return selected_list
;
882 /** Find objects entirely contained in a rectangle.
883 * @param layer The layer to search for objects in.
884 * @param rect The rectangle that the objects should be in.
885 * @return A list containing the objects that are entirely contained in the
886 * rectangle. The list should be freed by the caller.
889 layer_find_objects_in_rectangle(Layer
*layer
, Rectangle
*rect
)
892 GList
*selected_list
;
895 selected_list
= NULL
;
896 list
= layer
->objects
;
897 while (list
!= NULL
) {
899 obj
= (DiaObject
*)list
->data
;
901 if (rectangle_in_rectangle(rect
, &obj
->bounding_box
)) {
902 if (dia_object_is_selectable(obj
)) {
903 selected_list
= g_list_prepend(selected_list
, obj
);
907 list
= g_list_next(list
);
910 return selected_list
;
913 /** Find the object closest to the given point in the layer,
914 * no further away than maxdist, and not included in avoid.
915 * Stops it if finds an object that includes the point.
916 * @param layer The layer to search in.
917 * @param pos The point to compare to.
918 * @param maxdist The maximum distance the object can be from the point.
919 * @param avoid A list of objects that cannot be returned by this search.
920 * @return The closest object, or NULL if no allowed objects are closer than
924 layer_find_closest_object_except(Layer
*layer
, Point
*pos
,
925 real maxdist
, GList
*avoid
)
935 for (l
= layer
->objects
; l
!=NULL
; l
= g_list_next(l
)) {
936 obj
= (DiaObject
*) l
->data
;
938 /* Check bounding box here too. Might give speedup. */
939 dist
= obj
->ops
->distance_from(obj
, pos
);
941 if (maxdist
-dist
> 0.00000001) {
942 for (avoid_tmp
= avoid
; avoid_tmp
!= NULL
; avoid_tmp
= avoid_tmp
->next
) {
943 if (avoid_tmp
->data
== obj
) {
953 /* If the object is within a closed group, find the group. */
954 closest
= dia_object_get_parent_with_flags(closest
,
955 DIA_OBJECT_GRABS_CHILD_INPUT
);
960 /** Find the object closest to the given point in the layer,
961 * no further away than maxdist.
962 * Stops it if finds an object that includes the point.
963 * @param layer The layer to search in.
964 * @param pos The point to compare to.
965 * @param maxdist The maximum distance the object can be from the point.
966 * @return The closest object, or NULL if none are closer than maxdist.
969 layer_find_closest_object(Layer
*layer
, Point
*pos
, real maxdist
)
971 return layer_find_closest_object_except(layer
, pos
, maxdist
, NULL
);
975 /** Find the connectionpoint closest to pos in a layer.
983 layer_find_closest_connectionpoint(Layer
*layer
,
984 ConnectionPoint
**closest
,
994 mindist
= 1000000.0; /* Realy big value... */
998 for (l
= layer
->objects
; l
!=NULL
; l
= g_list_next(l
) ) {
999 obj
= (DiaObject
*) l
->data
;
1001 if (obj
== notthis
) continue;
1002 if (obj
!= dia_object_get_parent_with_flags(obj
, DIA_OBJECT_GRABS_CHILD_INPUT
))
1004 for (i
=0;i
<obj
->num_connections
;i
++) {
1005 cp
= obj
->connections
[i
];
1006 /* Note: Uses manhattan metric for speed... */
1007 dist
= distance_point_point_manhattan(pos
, &cp
->pos
);
1020 layer_update_extents(Layer
*layer
)
1024 Rectangle new_extents
;
1028 obj
= (DiaObject
*) l
->data
;
1029 new_extents
= obj
->bounding_box
;
1033 obj
= (DiaObject
*) l
->data
;
1034 rectangle_union(&new_extents
, &obj
->bounding_box
);
1038 new_extents
= invalid_extents
;
1041 if (rectangle_equals(&new_extents
,&layer
->extents
)) return FALSE
;
1043 layer
->extents
= new_extents
;
1048 layer_replace_object_with_list(Layer
*layer
, DiaObject
*remove_obj
,
1053 list
= g_list_find(layer
->objects
, remove_obj
);
1055 g_assert(list
!=NULL
);
1056 set_parent_layer(remove_obj
, NULL
);
1057 dynobj_list_remove_object(remove_obj
);
1058 g_list_foreach(insert_list
, set_parent_layer
, layer
);
1060 if (list
->prev
== NULL
) {
1061 layer
->objects
= insert_list
;
1063 list
->prev
->next
= insert_list
;
1064 insert_list
->prev
= list
->prev
;
1066 if (list
->next
!= NULL
) {
1068 last
= g_list_last(insert_list
);
1069 last
->next
= list
->next
;
1070 list
->next
->prev
= last
;
1072 g_list_free_1(list
);
1076 layer_remove_dynobj(gpointer obj
, gpointer userdata
)
1078 dynobj_list_remove_object((DiaObject
*)obj
);
1081 void layer_set_object_list(Layer
*layer
, GList
*list
)
1083 g_list_foreach(layer
->objects
, set_parent_layer
, NULL
);
1084 g_list_foreach(layer
->objects
, layer_remove_dynobj
, NULL
);
1085 g_list_free(layer
->objects
);
1086 layer
->objects
= list
;
1087 g_list_foreach(layer
->objects
, set_parent_layer
, layer
);
1091 layer_get_parent_diagram(Layer
*layer
)
1093 return layer
->parent_diagram
;