/** This is slightly more complex -- must see if any non-parented objects * are within a parenting object. */ static gboolean diagram_selected_can_parent(Diagram *dia) { GList *selected; GList *parents = NULL; for (selected = dia->data->selected; selected != NULL; selected = selected->next) { DiaObject *obj = (DiaObject*)selected->data; if (object_flags_set(obj, DIA_OBJECT_CAN_PARENT)) { parents = g_list_prepend(parents, obj); } } for (selected = dia->data->selected; selected != NULL; selected = selected->next) { DiaObject *obj = (DiaObject*)selected->data; if (obj->parent == NULL) { GList *parent_tmp; for (parent_tmp = parents; parent_tmp != NULL; parent_tmp = parent_tmp->next) { if (object_within_parent(obj, (DiaObject*)parent_tmp->data)) { g_list_free(parents); return TRUE; } } } } g_list_free(parents); return FALSE; }
/** Remove all children from the selected parents. */ void diagram_unparent_children_selected(Diagram *dia) { GList *list; DiaObject *obj, *child; gboolean any_unparented = FALSE; for (list = dia->data->selected; list != NULL; list = g_list_next(list)) { obj = (DiaObject *) list->data; if (!object_flags_set(obj, DIA_OBJECT_CAN_PARENT) || !obj->children) continue; any_unparented = TRUE; /* Yes, this creates a whole bunch of Changes. They're lightweight * structures, though, and it's easier to assure correctness this * way. If needed, we can make a parent undo with a list of children. */ while (obj->children != NULL) { Change *change; child = (DiaObject *) obj->children->data; change = undo_parenting(dia, obj, child, FALSE); /* This will remove one item from the list, so the while terminates. */ (change->apply)(change, dia); } if (obj->children != NULL) printf("Obj still has %d children\n", g_list_length(obj->children)); } if (any_unparented) { diagram_modified(dia); diagram_flush(dia); undo_set_transactionpoint(dia->undo); } }
static gboolean diagram_selected_any_parents(Diagram *dia) { GList *selected; for (selected = dia->data->selected; selected != NULL; selected = selected->next) { DiaObject *obj = (DiaObject*)selected->data; if (object_flags_set(obj, DIA_OBJECT_CAN_PARENT) && obj->children != NULL) return TRUE; } return FALSE; }
/* needs faster algorithm -- if we find that parenting is slow. * If it works, don't optimize it until it's a hotspot. */ void diagram_parent_selected(Diagram *dia) { GList *list = dia->data->selected; int length = g_list_length(list); int idx, idx2; ObjectExtent *oe; gboolean any_parented = FALSE; GPtrArray *extents = g_ptr_array_sized_new(length); while (list) { oe = g_new(ObjectExtent, 1); oe->object = list->data; parent_handle_extents(list->data, &oe->extent); g_ptr_array_add(extents, oe); list = g_list_next(list); } /* sort all the objects by their left position */ g_ptr_array_sort(extents, diagram_parent_sort_cb); for (idx = 0; idx < length; idx++) { ObjectExtent *oe1 = g_ptr_array_index(extents, idx); if (oe1->object->parent) continue; for (idx2 = idx + 1; idx2 < length; idx2++) { ObjectExtent *oe2 = g_ptr_array_index(extents, idx2); if (!object_flags_set(oe2->object, DIA_OBJECT_CAN_PARENT)) continue; if (oe1->extent.right <= oe2->extent.right && oe1->extent.bottom <= oe2->extent.bottom) { Change *change; change = undo_parenting(dia, oe2->object, oe1->object, TRUE); (change->apply)(change, dia); any_parented = TRUE; /* oe1->object->parent = oe2->object; oe2->object->children = g_list_append(oe2->object->children, oe1->object); */ break; } } } g_ptr_array_free(extents, TRUE); if (any_parented) { diagram_modified(dia); diagram_flush(dia); undo_set_transactionpoint(dia->undo); } }
/** Returns TRUE if an object is fully enclosed by a another object, which * can be a parent */ gboolean object_within_parent(DiaObject *obj, DiaObject *p) { Rectangle obj_bb = obj->bounding_box; if (!object_flags_set(p, DIA_OBJECT_CAN_PARENT)) return FALSE; if (p == obj) return FALSE; if (obj_bb.left > p->bounding_box.left && obj_bb.right < p->bounding_box.right && obj_bb.top > p->bounding_box.top && obj_bb.bottom < p->bounding_box.bottom) return TRUE; return FALSE; }
static void newgroup_update_data(NewGroup *group) { Element *elem = &group->element; /* ElementBBExtras *extra = &elem->extra_spacing; */ DiaObject *obj = &elem->object; /* Update connections: */ group->connections[0].pos.x = elem->corner.x; group->connections[0].pos.y = elem->corner.y; group->connections[1].pos.x = elem->corner.x + elem->width / 2.0; group->connections[1].pos.y = elem->corner.y; group->connections[2].pos.x = elem->corner.x + elem->width; group->connections[2].pos.y = elem->corner.y; group->connections[3].pos.x = elem->corner.x; group->connections[3].pos.y = elem->corner.y + elem->height / 2.0; group->connections[4].pos.x = elem->corner.x + elem->width; group->connections[4].pos.y = elem->corner.y + elem->height / 2.0; group->connections[5].pos.x = elem->corner.x; group->connections[5].pos.y = elem->corner.y + elem->height; group->connections[6].pos.x = elem->corner.x + elem->width / 2.0; group->connections[6].pos.y = elem->corner.y + elem->height; group->connections[7].pos.x = elem->corner.x + elem->width; group->connections[7].pos.y = elem->corner.y + elem->height; group->connections[8].pos.x = elem->corner.x + elem->width / 2.0; group->connections[8].pos.y = elem->corner.y + elem->height / 2.0; group->connections[0].directions = DIR_NORTH|DIR_WEST; group->connections[1].directions = DIR_NORTH; group->connections[2].directions = DIR_NORTH|DIR_EAST; group->connections[3].directions = DIR_WEST; group->connections[4].directions = DIR_EAST; group->connections[5].directions = DIR_SOUTH|DIR_WEST; group->connections[6].directions = DIR_SOUTH; group->connections[7].directions = DIR_SOUTH|DIR_EAST; group->connections[8].directions = DIR_ALL; element_update_boundingbox(elem); obj->position = elem->corner; element_update_handles(elem); if (group->is_open) { obj->flags &= ~DIA_OBJECT_GRABS_CHILD_INPUT; } else { gboolean newlySet = FALSE; Layer *layer; if (!object_flags_set(obj, DIA_OBJECT_GRABS_CHILD_INPUT)) { newlySet = TRUE; } obj->flags |= DIA_OBJECT_GRABS_CHILD_INPUT; if (newlySet) { layer = dia_object_get_parent_layer(obj); if (layer != NULL) { /* Placed in diagram already */ GList *children = g_list_prepend(NULL, obj); children = parent_list_affected(children); /* Remove the group object that stayed at the start of the list, leaving only the children */ children = g_list_remove_link(children, children); #if 0 /* this introduces a crircular dependency, does not work on win32 and is bad style everywhere */ diagram_unselect_objects(layer_get_parent_diagram(layer), children); #else g_warning ("used to call diagram_unselect_objects()"); #endif g_list_free(children); } } } }